Add option to preserve text shaders (#7786)

This commit is contained in:
Ben Doherty
2024-04-23 12:38:23 -04:00
committed by Benjamin Doherty
parent 76a8f18700
commit 2f36df8d93
3 changed files with 66 additions and 42 deletions

View File

@@ -287,7 +287,8 @@ bool compileMetalShaders(const std::vector<filamat::TextEntry>& mslEntries,
return true;
}
int externalCompile(utils::Path input, utils::Path output, std::vector<std::string> args) {
int externalCompile(utils::Path input, utils::Path output, bool preserveTextShaders,
std::vector<std::string> args) {
std::ifstream in(input.c_str(), std::ifstream::in | std::ios::binary);
if (!in.is_open()) {
std::cerr << "Could not open the source material " << input << std::endl;
@@ -333,18 +334,7 @@ int externalCompile(utils::Path input, utils::Path output, std::vector<std::stri
return 1;
}
// Since we're modifying text shaders, we'll need to regenerate the text dictionary.
// We'll also need to re-emit text based shaders that rely on the dictionary.
// Here we ONLY add GLSL and ESSL 1 types, as we're removing MSL completely.
filamat::LineDictionary textDictionary;
for (const auto& s : glslEntries) {
textDictionary.addText(s.shader);
}
for (const auto& s : essl1Entries) {
textDictionary.addText(s.shader);
}
// We'll also need to regenerate the SPIRV dictionary and SPIRV shaders.
// We always need to regenerate the SPIRV dictionary and SPIRV shaders.
// This is required, as the SPIRV blobs have alignment requirements. Since we're modifying other
// chunks, their alignment might have changed.
filamat::BlobDictionary spirvDictionary;
@@ -359,19 +349,28 @@ int externalCompile(utils::Path input, utils::Path output, std::vector<std::stri
e.dictionaryIndex = metalBinaryDictionary.addBlob(data);
}
bool removingMslShaders = !preserveTextShaders;
// Pass through chunks that don't need to change.
filamat::ChunkContainer outputChunks;
for (int i = 0; i < container.getChunkCount(); i++) {
filaflat::ChunkContainer::Chunk c = container.getChunk(i);
if (c.type == filamat::ChunkType::MaterialMetal) {
// This chunk is being removed, skip it.
continue;
if (removingMslShaders) {
if (c.type == filamat::ChunkType::MaterialMetal) {
// This chunk is being removed, skip it.
continue;
}
if (c.type == filamat::ChunkType::MaterialGlsl ||
c.type == filamat::ChunkType::MaterialEssl1 ||
c.type == filamat::ChunkType::DictionaryText) {
// These shader / dictionary chunks will be re-added below.
continue;
}
}
if (c.type == filamat::ChunkType::MaterialGlsl ||
c.type == filamat::ChunkType::MaterialEssl1 ||
c.type == filamat::ChunkType::MaterialSpirv ||
c.type == filamat::ChunkType::DictionarySpirv ||
c.type == filamat::ChunkType::DictionaryText) {
if (c.type == filamat::ChunkType::MaterialSpirv ||
c.type == filamat::ChunkType::DictionarySpirv) {
// These shader / dictionary chunks will be re-added below.
continue;
}
@@ -379,21 +378,34 @@ int externalCompile(utils::Path input, utils::Path output, std::vector<std::stri
reinterpret_cast<const char*>(c.desc.start), c.desc.size, c.type);
}
// Add the re-generated text dictionary chunk and text-based shaders.
if (!textDictionary.isEmpty()) {
const auto& dictionaryChunk = outputChunks.push<filamat::DictionaryTextChunk>(
std::move(textDictionary), filamat::ChunkType::DictionaryText);
// Re-emit GLSL chunk (MaterialTextChunk).
if (!glslEntries.empty()) {
outputChunks.push<filamat::MaterialTextChunk>(std::move(glslEntries),
dictionaryChunk.getDictionary(), filamat::ChunkType::MaterialGlsl);
if (removingMslShaders) {
// Since we're modifying text shaders, we'll need to regenerate the text dictionary.
// We'll also need to re-emit text based shaders that rely on the dictionary.
// Here we ONLY add GLSL and ESSL 1 types, as we're removing MSL completely.
filamat::LineDictionary textDictionary;
for (const auto& s : glslEntries) {
textDictionary.addText(s.shader);
}
for (const auto& s : essl1Entries) {
textDictionary.addText(s.shader);
}
// Re-emit ESSL1 chunk (MaterialTextChunk).
if (!essl1Entries.empty()) {
outputChunks.push<filamat::MaterialTextChunk>(std::move(essl1Entries),
dictionaryChunk.getDictionary(), filamat::ChunkType::MaterialEssl1);
// Add the re-generated text dictionary chunk and text-based shaders.
if (!textDictionary.isEmpty()) {
const auto& dictionaryChunk = outputChunks.push<filamat::DictionaryTextChunk>(
std::move(textDictionary), filamat::ChunkType::DictionaryText);
// Re-emit GLSL chunk (MaterialTextChunk).
if (!glslEntries.empty()) {
outputChunks.push<filamat::MaterialTextChunk>(std::move(glslEntries),
dictionaryChunk.getDictionary(), filamat::ChunkType::MaterialGlsl);
}
// Re-emit ESSL1 chunk (MaterialTextChunk).
if (!essl1Entries.empty()) {
outputChunks.push<filamat::MaterialTextChunk>(std::move(essl1Entries),
dictionaryChunk.getDictionary(), filamat::ChunkType::MaterialEssl1);
}
}
}

View File

@@ -24,7 +24,8 @@
namespace matedit {
int externalCompile(utils::Path input, utils::Path output, std::vector<std::string> args);
int externalCompile(utils::Path input, utils::Path output, bool preserveTextShaders,
std::vector<std::string> args);
} // namespace matedit

View File

@@ -28,6 +28,7 @@ struct Config {
utils::Path inputFile;
utils::Path outputFile;
std::vector<std::string> commandArgs;
bool preserveTextShaders = false;
};
static void printUsage(const char* name) {
@@ -55,6 +56,9 @@ static void printUsage(const char* name) {
" --type=[shader type], -t\n"
" Specify the shader type, currently only metal is supported\n"
"\n"
" --preserve-text-shaders, -p\n"
" Keep the text-based shaders when writing the output file\n"
"\n"
"Commands:\n"
" external-compile\n"
" Transforms all the text-based shaders of the specified type in the input file into binaries\n"
@@ -76,7 +80,8 @@ static void printUsage(const char* name) {
" <input shader> is guaranteed to have a .metal extension.\n"
" <output binary> is guaranteed to have a .metallib extension.\n"
"\n"
" This command will remove the text-based shaders when writing the output material file.\n"
" This command will remove the text-based shaders when writing the output material file, unless\n"
" the --preserve-text-shaders option is specified.\n"
"\n"
" If script exits with a non-zero exit code, MATEDIT will terminate with error. Multiple\n"
" invocations of script may be launched in parallel.\n"
@@ -93,12 +98,13 @@ static void printUsage(const char* name) {
}
static int handleArguments(int argc, char* argv[], Config* config) {
static constexpr const char* OPTSTR = "hi:o:t:";
static constexpr const char* OPTSTR = "hi:o:t:p";
static const struct option OPTIONS[] = {
{ "help", no_argument, nullptr, 'h' },
{ "input", required_argument, nullptr, 'i' },
{ "output", required_argument, nullptr, 'o' },
{ "type", required_argument, nullptr, 't' },
{ "help", no_argument, nullptr, 'h' },
{ "input", required_argument, nullptr, 'i' },
{ "output", required_argument, nullptr, 'o' },
{ "type", required_argument, nullptr, 't' },
{ "preserve-text-shaders", no_argument, nullptr, 'p' },
{ nullptr, 0, nullptr, 0 } // termination of the option list
};
@@ -126,6 +132,10 @@ static int handleArguments(int argc, char* argv[], Config* config) {
<< std::endl;
exit(1);
}
break;
case 'p':
config->preserveTextShaders = true;
break;
}
}
@@ -176,5 +186,6 @@ int main(int argc, char* argv[]) {
return 1;
}
return matedit::externalCompile(config.inputFile, config.outputFile, config.commandArgs);
return matedit::externalCompile(
config.inputFile, config.outputFile, config.preserveTextShaders, config.commandArgs);
}