Rework material Variant filters

Variants are no longer just a bit mask, but rather a combination of
some bits, depending on the variant. Because of that the variant filer
must be updated.

Basically we now make a distinction between the "variants" as a public
material API and the actual `Variant` data type.

This change does the impedance match between the two.
This commit is contained in:
Mathias Agopian
2022-02-08 14:36:07 -08:00
committed by Mathias Agopian
parent 8314bafc0e
commit cc0486b3cc
9 changed files with 171 additions and 96 deletions

View File

@@ -12,8 +12,9 @@ file(GLOB_RECURSE PUBLIC_HDRS ${PUBLIC_HDR_DIR}/**/*.h)
set(SRCS
src/SamplerBindingMap.cpp
src/SamplerInterfaceBlock.cpp
src/UniformInterfaceBlock.cpp
src/SibGenerator.cpp
src/UniformInterfaceBlock.cpp
src/Variant.cpp
)
# ==================================================================================================

View File

@@ -231,6 +231,17 @@ enum class Property : uint8_t {
// when adding new Properties, make sure to update MATERIAL_PROPERTIES_COUNT
};
enum class UserVariantFilterBit : uint32_t {
DIRECTIONAL_LIGHTING = 0x01,
DYNAMIC_LIGHTING = 0x02,
SHADOW_RECEIVER = 0x04,
SKINNING = 0x08,
FOG = 0x10,
VSM = 0x20,
};
using UserVariantFilterMask = uint32_t;
} // namespace filament
#endif

View File

@@ -20,6 +20,8 @@
#include <stdint.h>
#include <cstddef>
#include <filament/MaterialEnums.h>
#include <utils/bitset.h>
namespace filament {
@@ -152,6 +154,10 @@ struct Variant {
return !isValidStandardVariant(variant) && !isValidDepthVariant(variant);
}
static constexpr bool isValid(Variant variant) noexcept {
return isValidStandardVariant(variant) || isValidDepthVariant(variant);
}
static constexpr Variant filterVariantVertex(Variant variant) noexcept {
// filter out vertex variants that are not needed. For e.g. fog doesn't affect the
// vertex shader.
@@ -206,85 +212,15 @@ struct Variant {
return Variant(key & rhs);
}
static Variant filterUserVariant(
Variant variant, UserVariantFilterMask filterMask) noexcept;
private:
void set(bool v, type_t mask) noexcept {
key = (key & ~mask) | (v ? mask : type_t(0));
}
};
namespace details {
// compile time sanity-check tests
constexpr inline bool reserved_is_not_valid() noexcept {
for (Variant::type_t i = 0; i < VARIANT_COUNT; i++) {
const Variant variant(i);
bool is_valid = Variant::isValidDepthVariant(variant) ||
Variant::isValidStandardVariant(variant);
bool is_reserved = Variant::isReserved(variant);
if (is_valid == is_reserved) {
return false;
}
}
return true;
}
constexpr inline size_t reserved_variant_count() noexcept {
size_t count = 0;
for (Variant::type_t i = 0; i < VARIANT_COUNT; i++) {
const Variant variant(i);
if (Variant::isReserved(variant)) { count++; }
}
return count;
}
constexpr inline size_t valid_variant_count() noexcept {
size_t count = 0;
for (Variant::type_t i = 0; i < VARIANT_COUNT; i++) {
const Variant variant(i);
if (Variant::isValidDepthVariant(variant) ||
Variant::isValidStandardVariant(variant)) {
count++;
}
}
return count;
}
constexpr inline size_t vertex_variant_count() noexcept {
size_t count = 0;
for (Variant::type_t i = 0; i < VARIANT_COUNT; i++) {
const Variant variant(i);
if (Variant::isValidDepthVariant(variant) ||
Variant::isValidStandardVariant(variant)) {
if (Variant::isVertexVariant(variant)) {
count++;
}
}
}
return count;
}
constexpr inline size_t fragment_variant_count() noexcept {
size_t count = 0;
for (Variant::type_t i = 0; i < VARIANT_COUNT; i++) {
const Variant variant(i);
if (Variant::isValidDepthVariant(variant) ||
Variant::isValidStandardVariant(variant)) {
if (Variant::filterVariantFragment(variant).key == i) {
count++;
}
}
}
return count;
}
static_assert(reserved_is_not_valid());
static_assert(reserved_variant_count() == 82);
static_assert(valid_variant_count() == 46);
static_assert(vertex_variant_count() == 16 - (2 + 0) + 4 - 0); // 18
static_assert(fragment_variant_count() == 32 - (4 + 8) + 4 - 1); // 25
} // namespace details
} // namespace filament
#endif // TNT_FILABRIDGE_VARIANT_H

View File

@@ -0,0 +1,122 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <private/filament/Variant.h>
namespace filament {
Variant Variant::filterUserVariant(
Variant variant, UserVariantFilterMask filterMask) noexcept {
// these are easy to filter by just removing the corresponding bit
if (filterMask & (uint32_t)UserVariantFilterBit::DIRECTIONAL_LIGHTING) {
variant.key &= ~(filterMask & DIR);
}
if (filterMask & (uint32_t)UserVariantFilterBit::DYNAMIC_LIGHTING) {
variant.key &= ~(filterMask & DYN);
}
if (filterMask & (uint32_t)UserVariantFilterBit::SKINNING) {
variant.key &= ~(filterMask & SKN);
}
if (!isValidDepthVariant(variant)) {
// we can't remove FOG from depth variants, this would, in fact, remove picking
if (filterMask & (uint32_t)UserVariantFilterBit::FOG) {
variant.key &= ~(filterMask & FOG);
}
}
if (filterMask & (uint32_t)UserVariantFilterBit::SHADOW_RECEIVER) {
variant.key &= ~(filterMask & SRE);
}
if (filterMask & (uint32_t)UserVariantFilterBit::VSM) {
variant.key &= ~(filterMask & VSM);
}
return variant;
}
namespace details {
// compile time sanity-check tests
constexpr inline bool reserved_is_not_valid() noexcept {
for (Variant::type_t i = 0; i < VARIANT_COUNT; i++) {
const Variant variant(i);
bool is_valid = Variant::isValid(variant);
bool is_reserved = Variant::isReserved(variant);
if (is_valid == is_reserved) {
return false;
}
}
return true;
}
constexpr inline size_t reserved_variant_count() noexcept {
size_t count = 0;
for (Variant::type_t i = 0; i < VARIANT_COUNT; i++) {
const Variant variant(i);
if (Variant::isReserved(variant)) {
count++;
}
}
return count;
}
constexpr inline size_t valid_variant_count() noexcept {
size_t count = 0;
for (Variant::type_t i = 0; i < VARIANT_COUNT; i++) {
const Variant variant(i);
if (Variant::isValid(variant)) {
count++;
}
}
return count;
}
constexpr inline size_t vertex_variant_count() noexcept {
size_t count = 0;
for (Variant::type_t i = 0; i < VARIANT_COUNT; i++) {
const Variant variant(i);
if (Variant::isValid(variant)) {
if (Variant::isVertexVariant(variant)) {
count++;
}
}
}
return count;
}
constexpr inline size_t fragment_variant_count() noexcept {
size_t count = 0;
for (Variant::type_t i = 0; i < VARIANT_COUNT; i++) {
const Variant variant(i);
if (Variant::isValid(variant)) {
if (Variant::isFragmentVariant(variant)) {
count++;
}
}
}
return count;
}
static_assert(reserved_is_not_valid());
static_assert(reserved_variant_count() == 82);
static_assert(valid_variant_count() == 46);
static_assert(vertex_variant_count() == 16 - (2 + 0) + 4 - 0); // 18
static_assert(fragment_variant_count() == 32 - (4 + 8) + 4 - 1); // 25
} // namespace details
} // namespace filament

View File

@@ -118,7 +118,6 @@ protected:
.targetApi = TargetApi::OPENGL,
.targetLanguage = TargetLanguage::SPIRV
};
uint8_t mVariantFilter = 0;
// Keeps track of how many times MaterialBuilder::init() has been called without a call to
// MaterialBuilder::shutdown(). Internally, glslang does something similar. We keep track for
@@ -518,7 +517,7 @@ public:
MaterialBuilder& generateDebugInfo(bool generateDebugInfo) noexcept;
//! Specifies a list of variants that should be filtered out during code generation.
MaterialBuilder& variantFilter(uint8_t variantFilter) noexcept;
MaterialBuilder& variantFilter(filament::UserVariantFilterMask variantFilter) noexcept;
//! Adds a new preprocessor macro definition to the shader code. Can be called repeatedly.
MaterialBuilder& shaderDefine(const char* name, const char* value) noexcept;
@@ -635,7 +634,7 @@ public:
// returns a list of at least getParameterCount() parameters
const ParameterList& getParameters() const noexcept { return mParameters; }
uint8_t getVariantFilter() const { return mVariantFilter; }
filament::UserVariantFilterMask getVariantFilter() const { return mVariantFilter; }
/// @endcond
@@ -753,6 +752,8 @@ private:
bool mUseLegacyMorphing = false;
PreprocessorDefineList mDefines;
filament::UserVariantFilterMask mVariantFilter = {};
};
} // namespace filamat

View File

@@ -404,7 +404,7 @@ MaterialBuilder& MaterialBuilder::generateDebugInfo(bool generateDebugInfo) noex
return *this;
}
MaterialBuilder& MaterialBuilder::variantFilter(uint8_t variantFilter) noexcept {
MaterialBuilder& MaterialBuilder::variantFilter(filament::UserVariantFilterMask variantFilter) noexcept {
mVariantFilter = variantFilter;
return *this;
}

View File

@@ -21,24 +21,26 @@
namespace filamat {
std::vector<Variant> determineSurfaceVariants(
filament::Variant::type_t variantFilter, bool isLit, bool shadowMultiplier) {
filament::UserVariantFilterMask userVariantFilter, bool isLit, bool shadowMultiplier) {
std::vector<Variant> variants;
filament::Variant::type_t variantMask = ~variantFilter;
for (filament::Variant::type_t k = 0; k < filament::VARIANT_COUNT; k++) {
filament::Variant variant(k);
if (filament::Variant::isReserved(variant)) {
continue;
}
// Remove variants for unlit materials
filament::Variant v = filament::Variant::filterVariant(
variant & variantMask, isLit || shadowMultiplier);
filament::Variant filteredVariant =
filament::Variant::filterUserVariant(variant, userVariantFilter);
if (filament::Variant::filterVariantVertex(v) == variant) {
// Remove variants for unlit materials
filteredVariant = filament::Variant::filterVariant(
filteredVariant, isLit || shadowMultiplier);
if (filament::Variant::filterVariantVertex(filteredVariant) == variant) {
variants.emplace_back(variant, filament::backend::ShaderType::VERTEX);
}
if (filament::Variant::filterVariantFragment(v) == variant) {
if (filament::Variant::filterVariantFragment(filteredVariant) == variant) {
variants.emplace_back(variant, filament::backend::ShaderType::FRAGMENT);
}
}

View File

@@ -33,7 +33,7 @@ struct Variant {
};
std::vector<Variant> determineSurfaceVariants(
filament::Variant::type_t variantFilter, bool isLit, bool shadowMultiplier);
filament::UserVariantFilterMask, bool isLit, bool shadowMultiplier);
std::vector<Variant> determinePostProcessVariants();

View File

@@ -697,17 +697,19 @@ static bool processRefractionType(MaterialBuilder& builder, const JsonishValue&
static bool processVariantFilter(MaterialBuilder& builder, const JsonishValue& value) {
// We avoid using an initializer list for this particular map to avoid build errors that are
// due to static initialization ordering.
static const std::unordered_map<std::string, uint8_t> strToEnum = [] {
std::unordered_map<std::string, uint8_t> strToEnum;
strToEnum["directionalLighting"] = filament::Variant::DIR;
strToEnum["dynamicLighting"] = filament::Variant::DYN;
strToEnum["shadowReceiver"] = filament::Variant::SRE;
strToEnum["skinning"] = filament::Variant::SKN;
strToEnum["vsm"] = filament::Variant::VSM;
strToEnum["fog"] = filament::Variant::FOG;
using filament::Variant;
static const std::unordered_map<std::string, filament::UserVariantFilterBit> strToEnum = [] {
std::unordered_map<std::string, filament::UserVariantFilterBit> strToEnum;
strToEnum["directionalLighting"] = filament::UserVariantFilterBit::DIRECTIONAL_LIGHTING;
strToEnum["dynamicLighting"] = filament::UserVariantFilterBit::DYNAMIC_LIGHTING;
strToEnum["shadowReceiver"] = filament::UserVariantFilterBit::SHADOW_RECEIVER;
strToEnum["skinning"] = filament::UserVariantFilterBit::SKINNING;
strToEnum["vsm"] = filament::UserVariantFilterBit::VSM;
strToEnum["fog"] = filament::UserVariantFilterBit::FOG;
return strToEnum;
}();
uint8_t variantFilter = 0;
filament::UserVariantFilterMask variantFilter = {};
const JsonishArray* jsonArray = value.toJsonArray();
const auto& elements = jsonArray->getElements();
@@ -726,7 +728,7 @@ static bool processVariantFilter(MaterialBuilder& builder, const JsonishValue& v
" is not a valid variant" << std::endl;
}
variantFilter |= strToEnum.at(s);
variantFilter |= (uint32_t)strToEnum.at(s);
}
builder.variantFilter(variantFilter);