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:
committed by
Mathias Agopian
parent
8314bafc0e
commit
cc0486b3cc
@@ -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
|
||||
)
|
||||
|
||||
# ==================================================================================================
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
122
libs/filabridge/src/Variant.cpp
Normal file
122
libs/filabridge/src/Variant.cpp
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user