Repository: google/filament
File: libs/filamat/src/shaders/CodeGenerator.cpp (C++)

Code before:
        out << types[value.index()] << " " << name << " =  " << variableName << ";\n";
        return out;
    }
    if (mTargetLanguage == MaterialBuilderBase::TargetLanguage::SPIRV) {
        out << "layout (constant_id = " << id << ") const "
            << types[value.index()] << " " << name << " = " << constantString << ";\n";
    } else {
        out << "#ifndef SPIRV_CROSS_CONSTANT_ID_" << id << '\n'
            << "#define SPIRV_CROSS_CONSTANT_ID_" << id << " " << constantString << '\n'
            << "#endif" << '\n'
            << "const " << types[value.index()] << " " << name << " = SPIRV_CROSS_CONSTANT_ID_" << id
            << ";\n\n";
    }
    return out;
}

utils::io::sstream& CodeGenerator::generatePushConstants(utils::io::sstream& out,
        MaterialBuilder::PushConstantList const& pushConstants, size_t const layoutLocation) const {
    static constexpr char const* STRUCT_NAME = "Constants";

    // This is a workaround for WebGPU not supporting push constants for skinning.
    // We replace the push constant with a regular constant struct initialized to 0.
    if (mTargetApi == TargetApi::WEBGPU) {
        out << "struct " << STRUCT_NAME << " {\n";
        for (auto const& constant: pushConstants) {
            out << "    int " << constant.name.c_str() << ";\n";
        }
        out << "};\n";
        out << "const " << STRUCT_NAME << " " << PUSH_CONSTANT_STRUCT_VAR_NAME << " = "
            << STRUCT_NAME << "(0);\n";
        return out;
    }


    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";
    }

Review comment (suggestion):
We should not assume an int. See `constant.type`, which is an enum of either INT, FLOAT, BOOL. This is handled below with the `getType` lambda, which could be reused here. I know we expect one constant and it to be an int with value 0, but we can make the code a little easier to adjust in the event that spec constants become supported.

Code after:
        out << types[value.index()] << " " << name << " =  " << variableName << ";\n";
        return out;
    }
    if (mTargetLanguage == MaterialBuilderBase::TargetLanguage::SPIRV) {
        out << "layout (constant_id = " << id << ") const "
            << types[value.index()] << " " << name << " = " << constantString << ";\n";
    } else {
        out << "#ifndef SPIRV_CROSS_CONSTANT_ID_" << id << '\n'
            << "#define SPIRV_CROSS_CONSTANT_ID_" << id << " " << constantString << '\n'
            << "#endif" << '\n'
            << "const " << types[value.index()] << " " << name << " = SPIRV_CROSS_CONSTANT_ID_" << id
            << ";\n\n";
    }
    return out;
}

utils::io::sstream& CodeGenerator::generatePushConstants(utils::io::sstream& out,
        MaterialBuilder::PushConstantList const& pushConstants, size_t const layoutLocation) const {
    if (UTILS_UNLIKELY(pushConstants.empty())) {
        return out;
    }
    static constexpr char const* STRUCT_NAME = "Constants";

    auto const getType = [](ConstantType const& type) {
        switch (type) {
            case ConstantType::BOOL:
                return "bool";
            case ConstantType::INT:
                return "int";
            case ConstantType::FLOAT:
                return "float";
        }
    };
    // This is a workaround for WebGPU not supporting push constants for skinning.
    // We replace the push constant with a regular constant struct initialized to 0.
    if (mTargetApi == TargetApi::WEBGPU) {
        assert_invariant(
                pushConstants.size() == 1 &&
                "The current workaround for WebGPU push constants assumes for now that only 1");
        assert_invariant(pushConstants[0].name == CString("morphingBufferOffset") &&
                         "The current workaround for WebGPU push constants assumes only the "
                         "morphingBufferOffset constant is present.");
        assert_invariant(pushConstants[0].type == ConstantType::INT &&
                         "The current workaround for WebGPU push constants assumes "
                         "morphingBufferOffset is an integer type.");
        out << "struct " << STRUCT_NAME << " {\n";
        for (auto const& constant: pushConstants) {
            out << "    " << getType(constant.type) << " " << constant.name.c_str() << ";\n";
        }
        out << "};\n";
        out << "const " << STRUCT_NAME << " " << PUSH_CONSTANT_STRUCT_VAR_NAME << " = "