diff --git a/filament/backend/include/backend/Program.h b/filament/backend/include/backend/Program.h index 5258d86f0250..7cec72cd0c2c 100644 --- a/filament/backend/include/backend/Program.h +++ b/filament/backend/include/backend/Program.h @@ -39,6 +39,7 @@ class Program { static constexpr size_t SHADER_TYPE_COUNT = 3; static constexpr size_t UNIFORM_BINDING_COUNT = CONFIG_UNIFORM_BINDING_COUNT; static constexpr size_t SAMPLER_BINDING_COUNT = CONFIG_SAMPLER_BINDING_COUNT; + struct Sampler { utils::CString name = {}; // name of the sampler in the shader uint32_t binding = 0; // binding point of the sampler in the shader diff --git a/filament/backend/src/opengl/OpenGLDriver.cpp b/filament/backend/src/opengl/OpenGLDriver.cpp index 40b090ad7d59..4e4579cc4fcf 100644 --- a/filament/backend/src/opengl/OpenGLDriver.cpp +++ b/filament/backend/src/opengl/OpenGLDriver.cpp @@ -294,7 +294,16 @@ void OpenGLDriver::setPushConstant(backend::ShaderStage stage, uint8_t index, assert_invariant(mCurrentPushConstants && "Calling setPushConstant() before binding a pipeline"); - auto const& [location, type] = mCurrentPushConstants->get(stage, index); + assert_invariant(stage == ShaderStage::VERTEX || stage == ShaderStage::FRAGMENT); + utils::Slice> constants; + if (stage == ShaderStage::VERTEX) { + constants = mCurrentPushConstants->vertexConstants; + } else if (stage == ShaderStage::FRAGMENT) { + constants = mCurrentPushConstants->fragmentConstants; + } + + assert_invariant(index < constants.size()); + auto const& [location, type] = constants[index]; // This push constant wasn't found in the shader. It's ok to return without error-ing here. if (location < 0) { diff --git a/filament/backend/src/opengl/OpenGLDriver.h b/filament/backend/src/opengl/OpenGLDriver.h index a3b863cfa5c0..667262b715e6 100644 --- a/filament/backend/src/opengl/OpenGLDriver.h +++ b/filament/backend/src/opengl/OpenGLDriver.h @@ -66,10 +66,8 @@ namespace filament::backend { class OpenGLPlatform; class PixelBufferDescriptor; struct TargetBufferInfo; - class OpenGLProgram; class TimerQueryFactoryInterface; - struct PushConstantBundle; class OpenGLDriver final : public DriverBase { diff --git a/filament/backend/src/opengl/OpenGLProgram.cpp b/filament/backend/src/opengl/OpenGLProgram.cpp index e4aad92096a5..6c5eab9a4423 100644 --- a/filament/backend/src/opengl/OpenGLProgram.cpp +++ b/filament/backend/src/opengl/OpenGLProgram.cpp @@ -46,10 +46,11 @@ struct OpenGLProgram::LazyInitializationData { Program::UniformBlockInfo uniformBlockInfo; Program::SamplerGroupInfo samplerGroupInfo; std::array bindingUniformInfo; - utils::FixedCapacityVector pushConstants; - uint8_t pushConstantFragmentStageOffset; + utils::FixedCapacityVector vertexPushConstants; + utils::FixedCapacityVector fragmentPushConstants; }; + OpenGLProgram::OpenGLProgram() noexcept = default; OpenGLProgram::OpenGLProgram(OpenGLDriver& gld, Program&& program) noexcept @@ -61,30 +62,8 @@ OpenGLProgram::OpenGLProgram(OpenGLDriver& gld, Program&& program) noexcept } else { lazyInitializationData->uniformBlockInfo = std::move(program.getUniformBlockBindings()); } - - lazyInitializationData->pushConstantFragmentStageOffset = 0; - - auto& vertexConstants = program.getPushConstants(ShaderStage::VERTEX); - auto& fragmentConstants = program.getPushConstants(ShaderStage::FRAGMENT); - - size_t const totalConstantCount = vertexConstants.size() + fragmentConstants.size(); - if (totalConstantCount > 0) { - auto& allConstants = lazyInitializationData->pushConstants; - size_t const numVertexConstants = vertexConstants.size(); - - if (numVertexConstants > 0) { - allConstants = std::move(vertexConstants); - lazyInitializationData->pushConstantFragmentStageOffset = numVertexConstants; - } - - allConstants.reserve(totalConstantCount); - allConstants.resize(totalConstantCount); - - std::for_each(fragmentConstants.cbegin(), fragmentConstants.cend(), - [&allConstants](Program::PushConstant const& constant) { - allConstants.push_back(constant); - }); - } + lazyInitializationData->vertexPushConstants = std::move(program.getPushConstants(ShaderStage::VERTEX)); + lazyInitializationData->fragmentPushConstants = std::move(program.getPushConstants(ShaderStage::FRAGMENT)); ShaderCompilerService& compiler = gld.getShaderCompilerService(); mToken = compiler.createProgram(name, std::move(program)); @@ -113,6 +92,7 @@ OpenGLProgram::~OpenGLProgram() noexcept { } void OpenGLProgram::initialize(OpenGLDriver& gld) { + SYSTRACE_CALL(); assert_invariant(gl.program == 0); @@ -227,18 +207,19 @@ void OpenGLProgram::initializeProgramState(OpenGLContext& context, GLuint progra } mUsedBindingsCount = usedBindingCount; - // Push constant initialization - mPushConstantFragmentStageOffset = lazyInitializationData.pushConstantFragmentStageOffset; - auto const& constants = lazyInitializationData.pushConstants; - if (!constants.empty()) { - mPushConstants.reserve(constants.size()); - mPushConstants.resize(constants.size()); - - std::transform(constants.cbegin(), constants.cend(), mPushConstants.begin(), - [program](Program::PushConstant const& constant) -> std::pair { - GLint const loc = glGetUniformLocation(program, constant.name.c_str()); - return {loc, constant.type}; - }); + auto& vertexConstants = lazyInitializationData.vertexPushConstants; + auto& fragmentConstants = lazyInitializationData.fragmentPushConstants; + + size_t const totalConstantCount = vertexConstants.size() + fragmentConstants.size(); + if (totalConstantCount > 0) { + mPushConstants.reserve(totalConstantCount); + mPushConstantFragmentStageOffset = vertexConstants.size(); + auto const transformAndAdd = [&](Program::PushConstant const& constant) { + GLint const loc = glGetUniformLocation(program, constant.name.c_str()); + mPushConstants.push_back({loc, constant.type}); + }; + std::for_each(vertexConstants.cbegin(), vertexConstants.cend(), transformAndAdd); + std::for_each(fragmentConstants.cbegin(), fragmentConstants.cend(), transformAndAdd); } } diff --git a/filament/backend/src/opengl/OpenGLProgram.h b/filament/backend/src/opengl/OpenGLProgram.h index a0a50e0cc0c4..19be485ac6bd 100644 --- a/filament/backend/src/opengl/OpenGLProgram.h +++ b/filament/backend/src/opengl/OpenGLProgram.h @@ -27,6 +27,7 @@ #include #include +#include #include #include @@ -39,21 +40,8 @@ namespace filament::backend { class OpenGLDriver; struct PushConstantBundle { - uint8_t fragmentStageOffset = 0; - utils::FixedCapacityVector> const* constants = nullptr; - - inline std::pair const& get(ShaderStage stage, uint8_t index) const { - assert_invariant(stage == ShaderStage::VERTEX ||stage == ShaderStage::FRAGMENT); - - // Either we're asking for a fragment stage constant or we're asking for a vertex stage - // constant and the number of vertex stage constants is greater than 0. - assert_invariant(stage == ShaderStage::FRAGMENT || fragmentStageOffset > 0); - - uint8_t const offset = (stage == ShaderStage::VERTEX ? 0 : fragmentStageOffset) + index; - - assert_invariant(offset < constants->size()); - return (*constants)[offset]; - } + utils::Slice> vertexConstants; + utils::Slice> fragmentConstants; }; class OpenGLProgram : public HwProgram { @@ -97,9 +85,10 @@ class OpenGLProgram : public HwProgram { } gl; // 4 bytes PushConstantBundle getPushConstants() { + auto fragBegin = mPushConstants.begin() + mPushConstantFragmentStageOffset; return { - .fragmentStageOffset = mPushConstantFragmentStageOffset, - .constants = &mPushConstants, + .vertexConstants = utils::Slice(mPushConstants.begin(), fragBegin), + .fragmentConstants = utils::Slice(fragBegin, mPushConstants.end()), }; } @@ -137,8 +126,9 @@ class OpenGLProgram : public HwProgram { }; UniformsRecord const* mUniformsRecords = nullptr; // 8 bytes - // Store [location, type] pairs. - utils::FixedCapacityVector> mPushConstants; // 16 bytes + // Note that this can be replaced with a raw pointer and an uint8_t (for size) to reduce the + // size of the container to 9 bytes if there is a need in the future. + utils::FixedCapacityVector> mPushConstants;// 16 bytes }; // if OpenGLProgram is larger tha 64 bytes, it'll fall in a larger Handle bucket. diff --git a/filament/src/MaterialParser.cpp b/filament/src/MaterialParser.cpp index b5aeda47cde6..0304253b9055 100644 --- a/filament/src/MaterialParser.cpp +++ b/filament/src/MaterialParser.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include @@ -225,6 +226,14 @@ bool MaterialParser::getConstants(utils::FixedCapacityVector* return ChunkMaterialConstants::unflatten(unflattener, value); } +bool MaterialParser::getPushConstants(utils::CString* structVarName, + utils::FixedCapacityVector* value) const noexcept { + auto [start, end] = mImpl.mChunkContainer.getChunkRange(filamat::MaterialPushConstants); + if (start == end) return false; + Unflattener unflattener(start, end); + return ChunkMaterialPushConstants::unflatten(unflattener, structVarName, value); +} + bool MaterialParser::getDepthWriteSet(bool* value) const noexcept { return mImpl.getFromSimpleChunk(ChunkType::MaterialDepthWriteSet, value); } @@ -709,4 +718,46 @@ bool ChunkMaterialConstants::unflatten(filaflat::Unflattener& unflattener, return true; } +bool ChunkMaterialPushConstants::unflatten(filaflat::Unflattener& unflattener, + utils::CString* structVarName, + utils::FixedCapacityVector* materialPushConstants) { + assert_invariant(materialPushConstants); + + if (!unflattener.read(structVarName)) { + return false; + } + + // Read number of constants. + uint64_t numConstants = 0; + if (!unflattener.read(&numConstants)) { + return false; + } + + materialPushConstants->reserve(numConstants); + materialPushConstants->resize(numConstants); + + for (uint64_t i = 0; i < numConstants; i++) { + CString constantName; + uint8_t constantType = 0; + uint8_t shaderStage = 0; + + if (!unflattener.read(&constantName)) { + return false; + } + + if (!unflattener.read(&constantType)) { + return false; + } + + if (!unflattener.read(&shaderStage)) { + return false; + } + + (*materialPushConstants)[i].name = constantName; + (*materialPushConstants)[i].type = static_cast(constantType); + (*materialPushConstants)[i].stage = static_cast(shaderStage); + } + return true; +} + } // namespace filament diff --git a/filament/src/MaterialParser.h b/filament/src/MaterialParser.h index 2ec7f7c1cc42..b10a549d8b3d 100644 --- a/filament/src/MaterialParser.h +++ b/filament/src/MaterialParser.h @@ -47,6 +47,7 @@ class BufferInterfaceBlock; class SamplerInterfaceBlock; struct SubpassInfo; struct MaterialConstant; +struct MaterialPushConstant; class MaterialParser { public: @@ -79,6 +80,8 @@ class MaterialParser { bool getSamplerBlockBindings(SamplerGroupBindingInfoList* pSamplerGroupInfoList, SamplerBindingToNameMap* pSamplerBindingToNameMap) const noexcept; bool getConstants(utils::FixedCapacityVector* value) const noexcept; + bool getPushConstants(utils::CString* structVarName, + utils::FixedCapacityVector* value) const noexcept; using BindingUniformInfoContainer = utils::FixedCapacityVector< std::pair>; @@ -214,6 +217,11 @@ struct ChunkMaterialConstants { utils::FixedCapacityVector* materialConstants); }; +struct ChunkMaterialPushConstants { + static bool unflatten(filaflat::Unflattener& unflattener, utils::CString* structVarName, + utils::FixedCapacityVector* materialPushConstants); +}; + } // namespace filament #endif // TNT_FILAMENT_MATERIALPARSER_H diff --git a/filament/src/details/Material.cpp b/filament/src/details/Material.cpp index 15042d7b551e..909f4eaec5a8 100644 --- a/filament/src/details/Material.cpp +++ b/filament/src/details/Material.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -297,7 +298,7 @@ FMaterial::FMaterial(FEngine& engine, const Material::Builder& builder, processBlendingMode(parser); processSpecializationConstants(engine, builder, parser); - processPushConstants(engine, builder); + processPushConstants(engine, parser); processDepthVariants(engine, parser); // we can only initialize the default instance once we're initialized ourselves @@ -931,29 +932,40 @@ void FMaterial::processSpecializationConstants(FEngine& engine, Material::Builde } } -void FMaterial::processPushConstants(FEngine& engine, Material::Builder const& builder) { - // TODO: for testing and illustrating push constants. To be removed. - // auto& vertexPushConstant = mPushConstants[(uint8_t) ShaderStage::VERTEX]; - // vertexPushConstant.reserve(PUSH_CONSTANTS.size()); - // vertexPushConstant.resize(PUSH_CONSTANTS.size()); - - // constexpr size_t PREFIX_LEN = sizeof(PUSH_CONSTANT_STRUCT_VAR_NAME); - // constexpr size_t MAX_VAR_LEN = 30; - // constexpr size_t TOTAL_NAME_LEN = - // PREFIX_LEN + MAX_VAR_LEN + 2; // additional chars for '.' and for the ending 0. - // char buf[TOTAL_NAME_LEN]; - - // std::transform(PUSH_CONSTANTS.cbegin(), PUSH_CONSTANTS.cend(), vertexPushConstant.begin(), - // [&buf](std::pair const& constant) - // -> backend::Program::PushConstant { - // assert_invariant(strlen(constant.first) <= MAX_VAR_LEN); - // // The following will be pass to Program, where the "name" is needed for GL to - // // identify the location of the uniform. We prepend the struct name here to save - // // some work in the backend. - // snprintf(buf, TOTAL_NAME_LEN, "%s.%s", PUSH_CONSTANT_STRUCT_VAR_NAME, - // constant.first); - // return { utils::CString(buf), constant.second }; - // }); +void FMaterial::processPushConstants(FEngine& engine, MaterialParser const* parser) { + utils::FixedCapacityVector& vertexConstants = + mPushConstants[(uint8_t) ShaderStage::VERTEX]; + utils::FixedCapacityVector& fragmentConstants = + mPushConstants[(uint8_t) ShaderStage::FRAGMENT]; + + CString structVarName; + utils::FixedCapacityVector pushConstants; + parser->getPushConstants(&structVarName, &pushConstants); + + vertexConstants.reserve(pushConstants.size()); + fragmentConstants.reserve(pushConstants.size()); + + constexpr size_t MAX_NAME_LEN = 60; + char buf[MAX_NAME_LEN]; + uint8_t vertexCount = 0, fragmentCount = 0; + + std::for_each(pushConstants.cbegin(), pushConstants.cend(), + [&](MaterialPushConstant const& constant) { + snprintf(buf, sizeof(buf), "%s.%s", structVarName.c_str(), constant.name.c_str()); + + switch (constant.stage) { + case ShaderStage::VERTEX: + vertexConstants.push_back({utils::CString(buf), constant.type}); + vertexCount++; + break; + case ShaderStage::FRAGMENT: + fragmentConstants.push_back({utils::CString(buf), constant.type}); + fragmentCount++; + break; + case ShaderStage::COMPUTE: + break; + } + }); } void FMaterial::processDepthVariants(FEngine& engine, MaterialParser const* const parser) { diff --git a/filament/src/details/Material.h b/filament/src/details/Material.h index 8fb06851a806..617f9699501c 100644 --- a/filament/src/details/Material.h +++ b/filament/src/details/Material.h @@ -253,7 +253,7 @@ class FMaterial : public Material { void processSpecializationConstants(FEngine& engine, Material::Builder const& builder, MaterialParser const* parser); - void processPushConstants(FEngine& engine, Material::Builder const& builder); + void processPushConstants(FEngine& engine, MaterialParser const* parser); void processDepthVariants(FEngine& engine, MaterialParser const* parser); diff --git a/libs/filabridge/include/filament/MaterialChunkType.h b/libs/filabridge/include/filament/MaterialChunkType.h index c80ac7d8c911..4a4561c14a9a 100644 --- a/libs/filabridge/include/filament/MaterialChunkType.h +++ b/libs/filabridge/include/filament/MaterialChunkType.h @@ -53,6 +53,7 @@ enum UTILS_PUBLIC ChunkType : uint64_t { MaterialAttributeInfo = charTo64bitNum("MAT_ATTR"), MaterialProperties = charTo64bitNum("MAT_PROP"), MaterialConstants = charTo64bitNum("MAT_CONS"), + MaterialPushConstants = charTo64bitNum("MAT_PCON"), MaterialName = charTo64bitNum("MAT_NAME"), MaterialVersion = charTo64bitNum("MAT_VERS"), diff --git a/libs/filabridge/include/private/filament/EngineEnums.h b/libs/filabridge/include/private/filament/EngineEnums.h index 0b845426d88b..a35a68c7932e 100644 --- a/libs/filabridge/include/private/filament/EngineEnums.h +++ b/libs/filabridge/include/private/filament/EngineEnums.h @@ -72,19 +72,10 @@ enum class ReservedSpecializationConstants : uint8_t { CONFIG_STEREO_EYE_COUNT = 8, // don't change (hardcoded in ShaderCompilerService.cpp) }; -// Note that the following enum/arrays should be ordered so that the ids correspond to indices in -// the two vectors. enum class PushConstantIds { MORPHING_BUFFER_OFFSET = 0, }; -using PushConstantType = backend::ConstantType; - -constexpr char const PUSH_CONSTANT_STRUCT_VAR_NAME[] = "pushConstants"; -const utils::FixedCapacityVector> PUSH_CONSTANTS = { - { "morphingBufferOffset", PushConstantType::INT }, -}; - // This value is limited by UBO size, ES3.0 only guarantees 16 KiB. // It's also limited by the Froxelizer's record buffer data type (uint8_t). constexpr size_t CONFIG_MAX_LIGHT_COUNT = 256; diff --git a/libs/filamat/CMakeLists.txt b/libs/filamat/CMakeLists.txt index 4e97538f7261..2fc20d7e916e 100644 --- a/libs/filamat/CMakeLists.txt +++ b/libs/filamat/CMakeLists.txt @@ -23,7 +23,8 @@ set(COMMON_PRIVATE_HDRS src/eiff/MaterialInterfaceBlockChunk.h src/eiff/ShaderEntry.h src/eiff/SimpleFieldChunk.h - src/Includes.h) + src/Includes.h + src/PushConstantDefinitions.h) set(COMMON_SRCS src/eiff/Chunk.cpp diff --git a/libs/filamat/include/filamat/MaterialBuilder.h b/libs/filamat/include/filamat/MaterialBuilder.h index 4b66965d7465..c3045b942baf 100644 --- a/libs/filamat/include/filamat/MaterialBuilder.h +++ b/libs/filamat/include/filamat/MaterialBuilder.h @@ -245,6 +245,7 @@ class UTILS_PUBLIC MaterialBuilder : public MaterialBuilderBase { using CullingMode = filament::backend::CullingMode; using FeatureLevel = filament::backend::FeatureLevel; using StereoscopicType = filament::backend::StereoscopicType; + using ShaderStage = filament::backend::ShaderStage; enum class VariableQualifier : uint8_t { OUT @@ -692,6 +693,12 @@ class UTILS_PUBLIC MaterialBuilder : public MaterialBuilderBase { } defaultValue; }; + struct PushConstant { + utils::CString name; + ConstantType type; + ShaderStage stage; + }; + static constexpr size_t MATERIAL_PROPERTIES_COUNT = filament::MATERIAL_PROPERTIES_COUNT; using Property = filament::Property; @@ -720,6 +727,7 @@ class UTILS_PUBLIC MaterialBuilder : public MaterialBuilderBase { using SubpassList = Parameter[MAX_SUBPASS_COUNT]; using BufferList = std::vector>; using ConstantList = std::vector; + using PushConstantList = std::vector; // returns the number of parameters declared in this material uint8_t getParameterCount() const noexcept { return mParameterCount; } @@ -763,6 +771,10 @@ class UTILS_PUBLIC MaterialBuilder : public MaterialBuilderBase { void prepareToBuild(MaterialInfo& info) noexcept; + // Initialize internal push constants that will both be written to the shaders and material + // chunks (like user-defined spec constants). + void initPushConstants() noexcept; + // Return true if the shader is syntactically and semantically valid. // This method finds all the properties defined in the fragment and // vertex shaders of the material. @@ -829,6 +841,7 @@ class UTILS_PUBLIC MaterialBuilder : public MaterialBuilderBase { PropertyList mProperties; ParameterList mParameters; ConstantList mConstants; + PushConstantList mPushConstants; SubpassList mSubpasses; VariableList mVariables; OutputList mOutputs; diff --git a/libs/filamat/src/MaterialBuilder.cpp b/libs/filamat/src/MaterialBuilder.cpp index 9acf657353a0..ee897754f66f 100644 --- a/libs/filamat/src/MaterialBuilder.cpp +++ b/libs/filamat/src/MaterialBuilder.cpp @@ -20,6 +20,7 @@ #include "Includes.h" #include "MaterialVariants.h" +#include "PushConstantDefinitions.h" #include "shaders/SibGenerator.h" #include "shaders/UibGenerator.h" @@ -173,6 +174,8 @@ void MaterialBuilderBase::prepare(bool vulkanSemantics, MaterialBuilder::MaterialBuilder() : mMaterialName("Unnamed") { std::fill_n(mProperties, MATERIAL_PROPERTIES_COUNT, false); mShaderModels.reset(); + + initPushConstants(); } MaterialBuilder::~MaterialBuilder() = default; @@ -660,6 +663,19 @@ void MaterialBuilder::prepareToBuild(MaterialInfo& info) noexcept { info.userMaterialHasCustomDepth = false; } +void MaterialBuilder::initPushConstants() noexcept { + mPushConstants.reserve(PUSH_CONSTANTS.size()); + mPushConstants.resize(PUSH_CONSTANTS.size()); + std::transform(PUSH_CONSTANTS.cbegin(), PUSH_CONSTANTS.cend(), mPushConstants.begin(), + [](filament::MaterialPushConstant const& inConstant) -> PushConstant { + return { + .name = inConstant.name, + .type = inConstant.type, + .stage = inConstant.stage, + }; + }); +} + bool MaterialBuilder::findProperties(backend::ShaderStage type, MaterialBuilder::PropertyList& allProperties, CodeGenParams const& semanticCodeGenParams) noexcept { @@ -828,7 +844,7 @@ bool MaterialBuilder::generateShaders(JobSystem& jobSystem, const std::vector(std::move(constantsEntry)); + utils::FixedCapacityVector pushConstantsEntry(mPushConstants.size()); + std::transform(mPushConstants.begin(), mPushConstants.end(), pushConstantsEntry.begin(), + [](PushConstant const& c) { + return MaterialPushConstant(c.name.c_str(), c.type, c.stage); + }); + container.push( + utils::CString(PUSH_CONSTANT_STRUCT_VAR_NAME), std::move(pushConstantsEntry)); + // TODO: should we write the SSBO info? this would only be needed if we wanted to provide // an interface to set [get?] values in the buffer. But we can do that easily // with a c-struct (what about kotlin/java?). tbd. diff --git a/libs/filamat/src/PushConstantDefinitions.h b/libs/filamat/src/PushConstantDefinitions.h new file mode 100644 index 000000000000..244326969cde --- /dev/null +++ b/libs/filamat/src/PushConstantDefinitions.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2024 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. + */ + +#ifndef TNT_FILAMAT_PUSH_CONSTANT_DEFINTITIONS_H +#define TNT_FILAMAT_PUSH_CONSTANT_DEFINTITIONS_H + +#include +#include + +#include + +#include + +namespace filamat { + +constexpr char PUSH_CONSTANT_STRUCT_VAR_NAME[] = "pushConstants"; + +utils::FixedCapacityVector const PUSH_CONSTANTS = { + { + "morphingBufferOffset", + filament::backend::ConstantType::INT, + filament::backend::ShaderStage::VERTEX, + }, +}; + +// Make sure that the indices defined in filabridge match the actual array indices defined here. +static_assert(static_cast(filament::PushConstantIds::MORPHING_BUFFER_OFFSET) == 0u); + +}// namespace filamat + +#endif diff --git a/libs/filamat/src/eiff/MaterialInterfaceBlockChunk.cpp b/libs/filamat/src/eiff/MaterialInterfaceBlockChunk.cpp index bf16eb233f8c..5f92ca7356bf 100644 --- a/libs/filamat/src/eiff/MaterialInterfaceBlockChunk.cpp +++ b/libs/filamat/src/eiff/MaterialInterfaceBlockChunk.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include @@ -104,6 +105,24 @@ void MaterialConstantParametersChunk::flatten(Flattener& f) { // ------------------------------------------------------------------------------------------------ +MaterialPushConstantParametersChunk::MaterialPushConstantParametersChunk( + CString const& structVarName, utils::FixedCapacityVector constants) + : Chunk(ChunkType::MaterialPushConstants), + mStructVarName(structVarName), + mConstants(std::move(constants)) {} + +void MaterialPushConstantParametersChunk::flatten(Flattener& f) { + f.writeString(mStructVarName.c_str()); + f.writeUint64(mConstants.size()); + for (const auto& constant: mConstants) { + f.writeString(constant.name.c_str()); + f.writeUint8(static_cast(constant.type)); + f.writeUint8(static_cast(constant.stage)); + } +} + +// ------------------------------------------------------------------------------------------------ + MaterialUniformBlockBindingsChunk::MaterialUniformBlockBindingsChunk( utils::FixedCapacityVector> list) : Chunk(ChunkType::MaterialUniformBindings), diff --git a/libs/filamat/src/eiff/MaterialInterfaceBlockChunk.h b/libs/filamat/src/eiff/MaterialInterfaceBlockChunk.h index ba5f325234da..5faee0147a9e 100644 --- a/libs/filamat/src/eiff/MaterialInterfaceBlockChunk.h +++ b/libs/filamat/src/eiff/MaterialInterfaceBlockChunk.h @@ -31,6 +31,7 @@ class SamplerInterfaceBlock; class BufferInterfaceBlock; struct SubpassInfo; struct MaterialConstant; +struct MaterialPushConstant; } // namespace filament namespace filamat { @@ -88,6 +89,21 @@ class MaterialConstantParametersChunk final : public Chunk { // ------------------------------------------------------------------------------------------------ +class MaterialPushConstantParametersChunk final : public Chunk { +public: + explicit MaterialPushConstantParametersChunk(utils::CString const& structVarName, + utils::FixedCapacityVector constants); + ~MaterialPushConstantParametersChunk() final = default; + +private: + void flatten(Flattener&) final; + + utils::CString mStructVarName; + utils::FixedCapacityVector mConstants; +}; + +// ------------------------------------------------------------------------------------------------ + class MaterialUniformBlockBindingsChunk final : public Chunk { using Container = utils::FixedCapacityVector< std::pair>; diff --git a/libs/filamat/src/shaders/CodeGenerator.cpp b/libs/filamat/src/shaders/CodeGenerator.cpp index cb6fef4280e7..09a085a40761 100644 --- a/libs/filamat/src/shaders/CodeGenerator.cpp +++ b/libs/filamat/src/shaders/CodeGenerator.cpp @@ -17,9 +17,9 @@ #include "CodeGenerator.h" #include "MaterialInfo.h" +#include "../PushConstantDefinitions.h" #include "generated/shaders.h" -#include "private/filament/EngineEnums.h" #include @@ -35,44 +35,6 @@ using namespace filament; using namespace backend; using namespace utils; -namespace { - -io::sstream& generatePushConstantImpl(size_t const layoutLocation, bool const outputSpirv, - io::sstream& out) { - static constexpr char const* STRUCT_NAME = "Constants"; - auto const getType = [](PushConstantType const& type) { - switch (type) { - case PushConstantType::BOOL: - return "bool"; - case PushConstantType::INT: - return "int"; - case PushConstantType::FLOAT: - return "float"; - } - }; - - if (outputSpirv) { - out << "layout(push_constant) uniform " << STRUCT_NAME << " {\n "; - } else { - out << "struct " << STRUCT_NAME << " {\n"; - } - - for (auto const& [name, type] : PUSH_CONSTANTS) { - out << getType(type) << " " << name << ";\n"; - } - - if (outputSpirv) { - out << "} " << PUSH_CONSTANT_STRUCT_VAR_NAME << ";\n"; - } else { - out << "};\n"; - out << "LAYOUT_LOCATION(" << static_cast(layoutLocation) << ") uniform " << STRUCT_NAME - << " " << PUSH_CONSTANT_STRUCT_VAR_NAME << ";\n"; - } - return out; -} - -} // anonymous namespace - io::sstream& CodeGenerator::generateSeparator(io::sstream& out) { out << '\n'; return out; @@ -493,7 +455,8 @@ io::sstream& CodeGenerator::generateVariable(io::sstream& out, ShaderStage stage } io::sstream& CodeGenerator::generateShaderInputs(io::sstream& out, ShaderStage type, - const AttributeBitset& attributes, Interpolation interpolation) const { + const AttributeBitset& attributes, Interpolation interpolation, + MaterialBuilder::PushConstantList const& pushConstants) const { auto const& attributeDatabase = MaterialBuilder::getAttributeDatabase(); const char* shading = getInterpolationQualifier(interpolation); @@ -519,7 +482,7 @@ io::sstream& CodeGenerator::generateShaderInputs(io::sstream& out, ShaderStage t }); out << "\n"; - generatePushConstants(out, attributes.size()); + generatePushConstants(out, pushConstants, attributes.size()); } out << "\n"; @@ -948,11 +911,38 @@ utils::io::sstream& CodeGenerator::generateSpecializationConstant(utils::io::sst } utils::io::sstream& CodeGenerator::generatePushConstants(utils::io::sstream& out, - size_t const layoutLocation) const { - // TODO: for testing and illustrating push constants. To be removed. - // bool const outputSpirv = mTargetLanguage == TargetLanguage::SPIRV - // && mTargetApi != TargetApi::OPENGL; - // generatePushConstantImpl(layoutLocation, outputSpirv, out); + MaterialBuilder::PushConstantList const& pushConstants, size_t const layoutLocation) const { + static constexpr char const* STRUCT_NAME = "Constants"; + + bool const outputSpirv = + mTargetLanguage == TargetLanguage::SPIRV && mTargetApi != TargetApi::OPENGL; + auto const getType = [](ConstantType const& type) { + switch (type) { + case ConstantType::BOOL: + return "bool"; + case ConstantType::INT: + return "int"; + case ConstantType::FLOAT: + return "float"; + } + }; + if (outputSpirv) { + out << "layout(push_constant) uniform " << STRUCT_NAME << " {\n "; + } else { + out << "struct " << STRUCT_NAME << " {\n"; + } + + for (auto const& constant: pushConstants) { + out << getType(constant.type) << " " << constant.name.c_str() << ";\n"; + } + + if (outputSpirv) { + out << "} " << PUSH_CONSTANT_STRUCT_VAR_NAME << ";\n"; + } else { + out << "};\n"; + out << "LAYOUT_LOCATION(" << static_cast(layoutLocation) << ") uniform " << STRUCT_NAME + << " " << PUSH_CONSTANT_STRUCT_VAR_NAME << ";\n"; + } return out; } diff --git a/libs/filamat/src/shaders/CodeGenerator.h b/libs/filamat/src/shaders/CodeGenerator.h index 35b59b4a843a..233243f348c4 100644 --- a/libs/filamat/src/shaders/CodeGenerator.h +++ b/libs/filamat/src/shaders/CodeGenerator.h @@ -107,7 +107,8 @@ class UTILS_PRIVATE CodeGenerator { // generate declarations for non-custom "in" variables utils::io::sstream& generateShaderInputs(utils::io::sstream& out, ShaderStage type, - const filament::AttributeBitset& attributes, filament::Interpolation interpolation) const; + const filament::AttributeBitset& attributes, filament::Interpolation interpolation, + MaterialBuilder::PushConstantList const& pushConstants) const; static utils::io::sstream& generatePostProcessInputs(utils::io::sstream& out, ShaderStage type); // generate declarations for custom output variables @@ -157,6 +158,7 @@ class UTILS_PRIVATE CodeGenerator { const char* name, uint32_t id, std::variant value) const; utils::io::sstream& generatePushConstants(utils::io::sstream& out, + MaterialBuilder::PushConstantList const& pushConstants, size_t const layoutLocation) const; static utils::io::sstream& generatePostProcessGetters(utils::io::sstream& out, ShaderStage type); diff --git a/libs/filamat/src/shaders/ShaderGenerator.cpp b/libs/filamat/src/shaders/ShaderGenerator.cpp index 92508566857c..6ad24c01481b 100644 --- a/libs/filamat/src/shaders/ShaderGenerator.cpp +++ b/libs/filamat/src/shaders/ShaderGenerator.cpp @@ -304,6 +304,7 @@ ShaderGenerator::ShaderGenerator( MaterialBuilder::OutputList const& outputs, MaterialBuilder::PreprocessorDefineList const& defines, MaterialBuilder::ConstantList const& constants, + MaterialBuilder::PushConstantList const& pushConstants, CString const& materialCode, size_t lineOffset, CString const& materialVertexCode, size_t vertexLineOffset, MaterialBuilder::MaterialDomain materialDomain) noexcept { @@ -325,6 +326,7 @@ ShaderGenerator::ShaderGenerator( mMaterialDomain = materialDomain; mDefines = defines; mConstants = constants; + mPushConstants = pushConstants; if (mMaterialFragmentCode.empty()) { if (mMaterialDomain == MaterialBuilder::MaterialDomain::SURFACE) { @@ -418,7 +420,15 @@ std::string ShaderGenerator::createVertexProgram(ShaderModel shaderModel, attributes.set(VertexAttribute::MORPH_TANGENTS_3); } } - cg.generateShaderInputs(vs, ShaderStage::VERTEX, attributes, interpolation); + + MaterialBuilder::PushConstantList vertexPushConstants; + std::copy_if(mPushConstants.begin(), mPushConstants.end(), + std::back_insert_iterator(vertexPushConstants), + [](MaterialBuilder::PushConstant const& constant) { + return constant.stage == ShaderStage::VERTEX; + }); + cg.generateShaderInputs(vs, ShaderStage::VERTEX, attributes, interpolation, + vertexPushConstants); CodeGenerator::generateCommonTypes(vs, ShaderStage::VERTEX); @@ -519,9 +529,14 @@ std::string ShaderGenerator::createFragmentProgram(ShaderModel shaderModel, generateSurfaceMaterialVariantProperties(fs, mProperties, mDefines); - - cg.generateShaderInputs(fs, ShaderStage::FRAGMENT, - material.requiredAttributes, interpolation); + MaterialBuilder::PushConstantList fragmentPushConstants; + std::copy_if(mPushConstants.begin(), mPushConstants.end(), + std::back_insert_iterator(fragmentPushConstants), + [](MaterialBuilder::PushConstant const& constant) { + return constant.stage == ShaderStage::FRAGMENT; + }); + cg.generateShaderInputs(fs, ShaderStage::FRAGMENT, material.requiredAttributes, interpolation, + fragmentPushConstants); CodeGenerator::generateCommonTypes(fs, ShaderStage::FRAGMENT); diff --git a/libs/filamat/src/shaders/ShaderGenerator.h b/libs/filamat/src/shaders/ShaderGenerator.h index 59b7f2685abf..1b419f3b06ca 100644 --- a/libs/filamat/src/shaders/ShaderGenerator.h +++ b/libs/filamat/src/shaders/ShaderGenerator.h @@ -43,6 +43,7 @@ class ShaderGenerator { MaterialBuilder::OutputList const& outputs, MaterialBuilder::PreprocessorDefineList const& defines, MaterialBuilder::ConstantList const& constants, + MaterialBuilder::PushConstantList const& pushConstants, utils::CString const& materialCode, size_t lineOffset, utils::CString const& materialVertexCode, @@ -125,6 +126,7 @@ class ShaderGenerator { MaterialBuilder::MaterialDomain mMaterialDomain; MaterialBuilder::PreprocessorDefineList mDefines; MaterialBuilder::ConstantList mConstants; + MaterialBuilder::PushConstantList mPushConstants; utils::CString mMaterialFragmentCode; // fragment or compute code utils::CString mMaterialVertexCode; size_t mMaterialLineOffset;