mat: Store matc parameters in material packages (#9070)
This commit enhances the material compilation process by embedding the
`matc` command-line parameters directly into the compiled material file.
This feature is valuable for debugging, as it allows developers to
inspect the exact compilation settings used for a given material.
A key consideration is the potential for personally identifiable
information (PII) in the command-line arguments (e.g., file paths). To
address this, a `toPIISafeString` method has been implemented to filter
out PII-sensitive options before they are stored in the material.
With this change, the matc command below
/path/to/matc -a opengl --api vulkan -p desktop -g -o /path/to/my.filamat /path/to/my.mat
is stored to the package as below. (veryfied by running `matinfo my.filamat`)
Compilation Parameters: -a opengl --api vulkan -p desktop -g
This commit is contained in:
@@ -58,6 +58,7 @@ enum UTILS_PUBLIC ChunkType : uint64_t {
|
||||
|
||||
MaterialName = charTo64bitNum("MAT_NAME"),
|
||||
MaterialVersion = charTo64bitNum("MAT_VERS"),
|
||||
MaterialCompilationParameters = charTo64bitNum("MAT_CPRM"),
|
||||
MaterialCacheId = charTo64bitNum("MAT_UUID"),
|
||||
MaterialFeatureLevel = charTo64bitNum("MAT_FEAT"),
|
||||
MaterialShading = charTo64bitNum("MAT_SHAD"),
|
||||
|
||||
@@ -295,6 +295,9 @@ public:
|
||||
//! Set the file name of this material file. Used in error reporting.
|
||||
MaterialBuilder& fileName(const char* name) noexcept;
|
||||
|
||||
//! Set the commandline parameters of matc. Used for debugging purpose.
|
||||
MaterialBuilder& compilationParameters(const char* params) noexcept;
|
||||
|
||||
//! Set the shading model.
|
||||
MaterialBuilder& shading(Shading shading) noexcept;
|
||||
|
||||
@@ -876,6 +879,7 @@ private:
|
||||
|
||||
utils::CString mMaterialName;
|
||||
utils::CString mFileName;
|
||||
utils::CString mCompilationParameters;
|
||||
|
||||
class ShaderCode {
|
||||
public:
|
||||
|
||||
@@ -232,6 +232,11 @@ MaterialBuilder& MaterialBuilder::fileName(const char* name) noexcept {
|
||||
return *this;
|
||||
}
|
||||
|
||||
MaterialBuilder& MaterialBuilder::compilationParameters(const char* params) noexcept {
|
||||
mCompilationParameters = CString(params);
|
||||
return *this;
|
||||
}
|
||||
|
||||
MaterialBuilder& MaterialBuilder::material(const char* code, size_t const line) noexcept {
|
||||
mMaterialFragmentCode.setUnresolved(CString(code));
|
||||
mMaterialFragmentCode.setLineOffset(line);
|
||||
@@ -1594,6 +1599,8 @@ void MaterialBuilder::writeCommonChunks(ChunkContainer& container, MaterialInfo&
|
||||
container.emplace<uint32_t>(MaterialVersion, MATERIAL_VERSION);
|
||||
container.emplace<uint8_t>(MaterialFeatureLevel, (uint8_t)info.featureLevel);
|
||||
container.emplace<const char*>(MaterialName, mMaterialName.c_str_safe());
|
||||
container.emplace<const char*>(MaterialCompilationParameters,
|
||||
mCompilationParameters.c_str_safe());
|
||||
container.emplace<uint32_t>(MaterialShaderModels, mShaderModels.getValue());
|
||||
container.emplace<uint8_t>(ChunkType::MaterialDomain, static_cast<uint8_t>(mMaterialDomain));
|
||||
|
||||
|
||||
@@ -75,6 +75,8 @@ public:
|
||||
|
||||
virtual std::string toString() const noexcept = 0;
|
||||
|
||||
virtual std::string toPIISafeString() const noexcept = 0;
|
||||
|
||||
bool isDebug() const noexcept {
|
||||
return mDebug;
|
||||
}
|
||||
|
||||
@@ -107,6 +107,12 @@ static bool printMaterial(ostream& text, const ChunkContainer& container) {
|
||||
text << name.c_str() << endl;
|
||||
}
|
||||
|
||||
CString compilationParameters;
|
||||
if (read(container, MaterialCompilationParameters, &compilationParameters)) {
|
||||
text << " " << setw(alignment) << left << "Compilation Parameters: ";
|
||||
text << compilationParameters.c_str() << endl;
|
||||
}
|
||||
|
||||
text << endl;
|
||||
|
||||
text << "Shading:" << endl;
|
||||
|
||||
@@ -30,6 +30,53 @@ using namespace utils;
|
||||
|
||||
namespace matc {
|
||||
|
||||
static constexpr const char* OPTSTR = "hLxo:f:dm:a:l:p:D:T:P:OSEr:vV:gtwF1R";
|
||||
static const struct option OPTIONS[] = {
|
||||
{ "help", no_argument, nullptr, 'h' },
|
||||
{ "license", no_argument, nullptr, 'L' },
|
||||
{ "output", required_argument, nullptr, 'o' },
|
||||
{ "output-format", required_argument, nullptr, 'f' },
|
||||
{ "debug", no_argument, nullptr, 'd' },
|
||||
{ "variant-filter", required_argument, nullptr, 'V' },
|
||||
{ "platform", required_argument, nullptr, 'p' },
|
||||
{ "optimize", no_argument, nullptr, 'x' }, // for backward compatibility
|
||||
{ "optimize", no_argument, nullptr, 'O' }, // for backward compatibility
|
||||
{ "optimize-size", no_argument, nullptr, 'S' },
|
||||
{ "optimize-none", no_argument, nullptr, 'g' },
|
||||
{ "preprocessor-only", no_argument, nullptr, 'E' },
|
||||
{ "api", required_argument, nullptr, 'a' },
|
||||
{ "feature-level", required_argument, nullptr, 'l' },
|
||||
{ "no-essl1", no_argument, nullptr, '1' },
|
||||
{ "define", required_argument, nullptr, 'D' },
|
||||
{ "template", required_argument, nullptr, 'T' },
|
||||
{ "material-parameter",required_argument, nullptr, 'P' },
|
||||
{ "reflect", required_argument, nullptr, 'r' },
|
||||
{ "print", no_argument, nullptr, 't' },
|
||||
{ "version", no_argument, nullptr, 'v' },
|
||||
{ "raw", no_argument, nullptr, 'w' },
|
||||
{ "no-sampler-validation", no_argument, nullptr, 'F' },
|
||||
{ "save-raw-variants", no_argument, nullptr, 'R' },
|
||||
{ nullptr, 0, nullptr, 0 } // termination of the option list
|
||||
};
|
||||
|
||||
// A list of options that may contain PII(Personally Identifiable Information) data.
|
||||
// We ignore these options when we call the `toPIISafeString` method.
|
||||
static const std::string_view PII_OPTIONS[] = {
|
||||
"output",
|
||||
};
|
||||
|
||||
static bool isPIIOption(const char* longOptionName) {
|
||||
if (!longOptionName) {
|
||||
return false;
|
||||
}
|
||||
for (auto option : PII_OPTIONS) {
|
||||
if (option == longOptionName) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void usage(char* name) {
|
||||
std::string exec_name(utils::Path(name).getName());
|
||||
std::string usage(
|
||||
@@ -181,35 +228,6 @@ static void parseDefine(std::string defineString, matp::Config::StringReplacemen
|
||||
}
|
||||
|
||||
bool CommandlineConfig::parse() {
|
||||
static constexpr const char* OPTSTR = "hLxo:f:dm:a:l:p:D:T:P:OSEr:vV:gtwF1R";
|
||||
static const struct option OPTIONS[] = {
|
||||
{ "help", no_argument, nullptr, 'h' },
|
||||
{ "license", no_argument, nullptr, 'L' },
|
||||
{ "output", required_argument, nullptr, 'o' },
|
||||
{ "output-format", required_argument, nullptr, 'f' },
|
||||
{ "debug", no_argument, nullptr, 'd' },
|
||||
{ "variant-filter", required_argument, nullptr, 'V' },
|
||||
{ "platform", required_argument, nullptr, 'p' },
|
||||
{ "optimize", no_argument, nullptr, 'x' }, // for backward compatibility
|
||||
{ "optimize", no_argument, nullptr, 'O' }, // for backward compatibility
|
||||
{ "optimize-size", no_argument, nullptr, 'S' },
|
||||
{ "optimize-none", no_argument, nullptr, 'g' },
|
||||
{ "preprocessor-only", no_argument, nullptr, 'E' },
|
||||
{ "api", required_argument, nullptr, 'a' },
|
||||
{ "feature-level", required_argument, nullptr, 'l' },
|
||||
{ "no-essl1", no_argument, nullptr, '1' },
|
||||
{ "define", required_argument, nullptr, 'D' },
|
||||
{ "template", required_argument, nullptr, 'T' },
|
||||
{ "material-parameter",required_argument, nullptr, 'P' },
|
||||
{ "reflect", required_argument, nullptr, 'r' },
|
||||
{ "print", no_argument, nullptr, 't' },
|
||||
{ "version", no_argument, nullptr, 'v' },
|
||||
{ "raw", no_argument, nullptr, 'w' },
|
||||
{ "no-sampler-validation", no_argument, nullptr, 'F' },
|
||||
{ "save-raw-variants", no_argument, nullptr, 'R' },
|
||||
{ nullptr, 0, nullptr, 0 } // termination of the option list
|
||||
};
|
||||
|
||||
int opt;
|
||||
int option_index = 0;
|
||||
|
||||
@@ -348,4 +366,72 @@ bool CommandlineConfig::parse() {
|
||||
return true;
|
||||
}
|
||||
|
||||
// This method concatenates all options and arguments, excluding the executable name, input file
|
||||
// name, and any options found in PII_OPTIONS due to potential PII data.
|
||||
std::string CommandlineConfig::toPIISafeString() const noexcept {
|
||||
std::string result;
|
||||
optind = 1; // Reset getopt's internal index before parsing
|
||||
|
||||
while (true) {
|
||||
// getopt_long will only set `long_index` if a long option is parsed.
|
||||
int long_index = -1;
|
||||
int opt = getopt_long(mArgc, mArgv, OPTSTR, OPTIONS, &long_index);
|
||||
if (opt == -1) {
|
||||
break; // End of options
|
||||
}
|
||||
|
||||
// Find the matched option.
|
||||
const struct option* matched_option = nullptr;
|
||||
if (long_index != -1) {
|
||||
// A long option was parsed (e.g., --help)
|
||||
matched_option = &OPTIONS[long_index];
|
||||
} else if (opt > 0) {
|
||||
// A short option was parsed (e.g., -h)
|
||||
for (int i = 0; OPTIONS[i].name != nullptr; ++i) {
|
||||
if (OPTIONS[i].val == opt) {
|
||||
matched_option = &OPTIONS[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!matched_option) {
|
||||
std::cerr << "Failed to find the matched option: long_index=" << long_index
|
||||
<< ", opt=" << opt << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip if it's a PII option.
|
||||
if (isPIIOption(matched_option->name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Reconstruct the option.
|
||||
if (long_index != -1) {
|
||||
result += "--";
|
||||
result += matched_option->name;
|
||||
result += " ";
|
||||
} else if (opt > 0) {
|
||||
result += "-";
|
||||
result += (char)matched_option->val;
|
||||
result += " ";
|
||||
}
|
||||
|
||||
// Add an argument if available.
|
||||
if (optarg && matched_option && matched_option->has_arg != no_argument) {
|
||||
result += optarg;
|
||||
result += " ";
|
||||
}
|
||||
}
|
||||
|
||||
// We're ignoring the last (remaining) argument because it's user input with PII.
|
||||
|
||||
// Trim trailing space
|
||||
if (!result.empty()) {
|
||||
result.pop_back();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace matc
|
||||
|
||||
@@ -122,6 +122,8 @@ public:
|
||||
return parameters;
|
||||
}
|
||||
|
||||
std::string toPIISafeString() const noexcept override;
|
||||
|
||||
private:
|
||||
bool parse();
|
||||
|
||||
|
||||
@@ -76,6 +76,8 @@ bool MaterialCompiler::run(const matp::Config& config) {
|
||||
return true;
|
||||
}
|
||||
|
||||
builder.compilationParameters(config.toPIISafeString().c_str());
|
||||
|
||||
JobSystem js;
|
||||
js.adopt();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user