From cc0486b3cccec10fe85ff53763d6844cfc01f8cc Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Tue, 8 Feb 2022 14:36:07 -0800 Subject: [PATCH] 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. --- libs/filabridge/CMakeLists.txt | 3 +- .../include/filament/MaterialEnums.h | 11 ++ .../include/private/filament/Variant.h | 82 ++---------- libs/filabridge/src/Variant.cpp | 122 ++++++++++++++++++ .../filamat/include/filamat/MaterialBuilder.h | 7 +- libs/filamat/src/MaterialBuilder.cpp | 2 +- libs/filamat/src/MaterialVariants.cpp | 16 ++- libs/filamat/src/MaterialVariants.h | 2 +- tools/matc/src/matc/ParametersProcessor.cpp | 22 ++-- 9 files changed, 171 insertions(+), 96 deletions(-) create mode 100644 libs/filabridge/src/Variant.cpp diff --git a/libs/filabridge/CMakeLists.txt b/libs/filabridge/CMakeLists.txt index 0d42bb51d3..9ebefd2db9 100644 --- a/libs/filabridge/CMakeLists.txt +++ b/libs/filabridge/CMakeLists.txt @@ -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 ) # ================================================================================================== diff --git a/libs/filabridge/include/filament/MaterialEnums.h b/libs/filabridge/include/filament/MaterialEnums.h index ff724ff981..cfe81369db 100644 --- a/libs/filabridge/include/filament/MaterialEnums.h +++ b/libs/filabridge/include/filament/MaterialEnums.h @@ -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 diff --git a/libs/filabridge/include/private/filament/Variant.h b/libs/filabridge/include/private/filament/Variant.h index 37f75192e6..e93b3d7dd6 100644 --- a/libs/filabridge/include/private/filament/Variant.h +++ b/libs/filabridge/include/private/filament/Variant.h @@ -20,6 +20,8 @@ #include #include +#include + #include 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 diff --git a/libs/filabridge/src/Variant.cpp b/libs/filabridge/src/Variant.cpp new file mode 100644 index 0000000000..10dde5a0d8 --- /dev/null +++ b/libs/filabridge/src/Variant.cpp @@ -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 + +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 diff --git a/libs/filamat/include/filamat/MaterialBuilder.h b/libs/filamat/include/filamat/MaterialBuilder.h index 000d9dfbc9..8b19538adf 100644 --- a/libs/filamat/include/filamat/MaterialBuilder.h +++ b/libs/filamat/include/filamat/MaterialBuilder.h @@ -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 diff --git a/libs/filamat/src/MaterialBuilder.cpp b/libs/filamat/src/MaterialBuilder.cpp index 0865fc9291..3aca992a8f 100644 --- a/libs/filamat/src/MaterialBuilder.cpp +++ b/libs/filamat/src/MaterialBuilder.cpp @@ -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; } diff --git a/libs/filamat/src/MaterialVariants.cpp b/libs/filamat/src/MaterialVariants.cpp index 85f81cabd1..101887d3fc 100644 --- a/libs/filamat/src/MaterialVariants.cpp +++ b/libs/filamat/src/MaterialVariants.cpp @@ -21,24 +21,26 @@ namespace filamat { std::vector determineSurfaceVariants( - filament::Variant::type_t variantFilter, bool isLit, bool shadowMultiplier) { + filament::UserVariantFilterMask userVariantFilter, bool isLit, bool shadowMultiplier) { std::vector 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); } } diff --git a/libs/filamat/src/MaterialVariants.h b/libs/filamat/src/MaterialVariants.h index 25dcc090bb..3e6ea5711d 100644 --- a/libs/filamat/src/MaterialVariants.h +++ b/libs/filamat/src/MaterialVariants.h @@ -33,7 +33,7 @@ struct Variant { }; std::vector determineSurfaceVariants( - filament::Variant::type_t variantFilter, bool isLit, bool shadowMultiplier); + filament::UserVariantFilterMask, bool isLit, bool shadowMultiplier); std::vector determinePostProcessVariants(); diff --git a/tools/matc/src/matc/ParametersProcessor.cpp b/tools/matc/src/matc/ParametersProcessor.cpp index 33ae4d1ce7..187c47ba1e 100644 --- a/tools/matc/src/matc/ParametersProcessor.cpp +++ b/tools/matc/src/matc/ParametersProcessor.cpp @@ -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 strToEnum = [] { - std::unordered_map 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 strToEnum = [] { + std::unordered_map 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);