MoltenVKShaderConverter updates.

mvk::getShaderOutputs() in SPRIVReflection.h support flattening nested structures.
MoltenVKShaderConverter tool support loading tessellation shader files.
MoltenVKShaderConverter tool update to MSL 2.4 by default.
Remove use of deprecated MTLCreateSystemDefaultDevice().
Update to latest version of SPIRV-Cross.
This commit is contained in:
Bill Hollings 2022-01-18 12:37:59 -05:00
parent a8149aa45e
commit d4daba6687
5 changed files with 90 additions and 46 deletions

View File

@ -1 +1 @@
e9cc6403341baf0edd430a4027b074d0a06b782f
53d94a982e1d654515b44db5391de37f85489204

View File

@ -173,6 +173,42 @@ namespace mvk {
#endif
}
auto addSat = [](uint32_t a, uint32_t b) { return a == uint32_t(-1) ? a : a + b; };
template<typename Vo>
static inline uint32_t getShaderOutputStructMembers(const SPIRV_CROSS_NAMESPACE::CompilerReflection& reflect, Vo& outputs,
const SPIRV_CROSS_NAMESPACE::SPIRType* structType, spv::StorageClass storage,
bool patch, uint32_t loc) {
bool isUsed = true;
auto biType = spv::BuiltInMax;
size_t mbrCnt = structType->member_types.size();
for (uint32_t mbrIdx = 0; mbrIdx < mbrCnt; mbrIdx++) {
// Each member may have a location decoration. If not, each member
// gets an incrementing location based on the base location for the struct.
uint32_t cmp = 0;
if (reflect.has_member_decoration(structType->self, mbrIdx, spv::DecorationLocation)) {
loc = reflect.get_member_decoration(structType->self, mbrIdx, spv::DecorationLocation);
cmp = reflect.get_member_decoration(structType->self, mbrIdx, spv::DecorationComponent);
}
patch = patch || reflect.has_member_decoration(structType->self, mbrIdx, spv::DecorationPatch);
if (reflect.has_member_decoration(structType->self, mbrIdx, spv::DecorationBuiltIn)) {
biType = (spv::BuiltIn)reflect.get_member_decoration(structType->self, mbrIdx, spv::DecorationBuiltIn);
isUsed = reflect.has_active_builtin(biType, storage);
}
const SPIRV_CROSS_NAMESPACE::SPIRType* type = &reflect.get_type(structType->member_types[mbrIdx]);
uint32_t elemCnt = (type->array.empty() ? 1 : type->array[0]) * type->columns;
for (uint32_t i = 0; i < elemCnt; i++) {
if (type->basetype == SPIRV_CROSS_NAMESPACE::SPIRType::Struct)
loc = getShaderOutputStructMembers(reflect, outputs, type, storage, patch, loc);
else {
outputs.push_back({type->basetype, type->vecsize, loc, cmp, biType, patch, isUsed});
loc = addSat(loc, 1);
}
}
}
return loc;
}
/** Given a shader in SPIR-V format, returns output reflection data. */
template<typename Vs, typename Vo>
static inline bool getShaderOutputs(const Vs& spirv, spv::ExecutionModel model, const std::string& entryName,
@ -191,7 +227,6 @@ namespace mvk {
outputs.clear();
auto addSat = [](uint32_t a, uint32_t b) { return a == uint32_t(-1) ? a : a + b; };
for (auto varID : reflect.get_active_interface_variables()) {
spv::StorageClass storage = reflect.get_storage_class(varID);
if (storage != spv::StorageClassOutput) { continue; }
@ -215,47 +250,14 @@ namespace mvk {
if (model == spv::ExecutionModelTessellationControl && !patch)
type = &reflect.get_type(type->parent_type);
if (type->basetype == SPIRV_CROSS_NAMESPACE::SPIRType::Struct) {
uint32_t memberLoc = loc;
for (uint32_t idx = 0; idx < type->member_types.size(); idx++) {
// Each member may have a location decoration. If not, each member
// gets an incrementing location based the base location for the struct.
uint32_t memberCmp = 0;
if (reflect.has_member_decoration(type->self, idx, spv::DecorationLocation)) {
memberLoc = reflect.get_member_decoration(type->self, idx, spv::DecorationLocation);
memberCmp = reflect.get_member_decoration(type->self, idx, spv::DecorationComponent);
}
patch = patch || reflect.has_member_decoration(type->self, idx, spv::DecorationPatch);
if (reflect.has_member_decoration(type->self, idx, spv::DecorationBuiltIn)) {
biType = (spv::BuiltIn)reflect.get_member_decoration(type->self, idx, spv::DecorationBuiltIn);
isUsed = reflect.has_active_builtin(biType, storage);
}
const SPIRV_CROSS_NAMESPACE::SPIRType& memberType = reflect.get_type(type->member_types[idx]);
if (memberType.columns > 1) {
for (uint32_t i = 0; i < memberType.columns; i++) {
outputs.push_back({memberType.basetype, memberType.vecsize, memberLoc, memberCmp, biType, patch, isUsed});
memberLoc = addSat(memberLoc, 1);
}
} else if (!memberType.array.empty()) {
for (uint32_t i = 0; i < memberType.array[0]; i++) {
outputs.push_back({memberType.basetype, memberType.vecsize, memberLoc, memberCmp, biType, patch, isUsed});
memberLoc = addSat(memberLoc, 1);
}
} else {
outputs.push_back({memberType.basetype, memberType.vecsize, memberLoc, memberCmp, biType, patch, isUsed});
memberLoc = addSat(memberLoc, 1);
}
uint32_t elemCnt = (type->array.empty() ? 1 : type->array[0]) * type->columns;
for (uint32_t i = 0; i < elemCnt; i++) {
if (type->basetype == SPIRV_CROSS_NAMESPACE::SPIRType::Struct)
loc = getShaderOutputStructMembers(reflect, outputs, type, storage, patch, loc);
else {
outputs.push_back({type->basetype, type->vecsize, loc, cmp, biType, patch, isUsed});
loc = addSat(loc, 1);
}
} else if (type->columns > 1) {
for (uint32_t i = 0; i < type->columns; i++) {
outputs.push_back({type->basetype, type->vecsize, addSat(loc, i), cmp, biType, patch, isUsed});
}
} else if (!type->array.empty()) {
for (uint32_t i = 0; i < type->array[0]; i++) {
outputs.push_back({type->basetype, type->vecsize, addSat(loc, i), cmp, biType, patch, isUsed});
}
} else {
outputs.push_back({type->basetype, type->vecsize, loc, cmp, biType, patch, isUsed});
}
}
// Sort outputs by ascending location.

View File

@ -31,6 +31,12 @@ using namespace mvk;
// The default list of vertex file extensions.
static const char* _defaultVertexShaderExtns = "vs vsh vert vertex";
// The default list of tessellation control file extensions.
static const char* _defaultTescShaderExtns = "tcs tcsh tesc";
// The default list of tessellation evaluation file extensions.
static const char* _defaultTeseShaderExtns = "tes tesh tese";
// The default list of fragment file extensions.
static const char* _defaultFragShaderExtns = "fs fsh frag fragment";
@ -261,6 +267,8 @@ bool MoltenVKShaderConverterTool::convertSPIRV(const vector<uint32_t>& spv,
MVKGLSLConversionShaderStage MoltenVKShaderConverterTool::shaderStageFromFileExtension(string& pathExtension) {
for (auto& fx : _glslVtxFileExtns) { if (fx == pathExtension) { return kMVKGLSLConversionShaderStageVertex; } }
for (auto& fx : _glslTescFileExtns) { if (fx == pathExtension) { return kMVKGLSLConversionShaderStageTessControl; } }
for (auto& fx : _glslTeseFileExtns) { if (fx == pathExtension) { return kMVKGLSLConversionShaderStageTessEval; } }
for (auto& fx : _glslFragFileExtns) { if (fx == pathExtension) { return kMVKGLSLConversionShaderStageFragment; } }
for (auto& fx : _glslCompFileExtns) { if (fx == pathExtension) { return kMVKGLSLConversionShaderStageCompute; } }
return kMVKGLSLConversionShaderStageAuto;
@ -268,6 +276,8 @@ MVKGLSLConversionShaderStage MoltenVKShaderConverterTool::shaderStageFromFileExt
bool MoltenVKShaderConverterTool::isGLSLFileExtension(string& pathExtension) {
for (auto& fx : _glslVtxFileExtns) { if (fx == pathExtension) { return true; } }
for (auto& fx : _glslTescFileExtns) { if (fx == pathExtension) { return true; } }
for (auto& fx : _glslTeseFileExtns) { if (fx == pathExtension) { return true; } }
for (auto& fx : _glslFragFileExtns) { if (fx == pathExtension) { return true; } }
for (auto& fx : _glslCompFileExtns) { if (fx == pathExtension) { return true; } }
return false;
@ -344,6 +354,10 @@ void MoltenVKShaderConverterTool::showUsage() {
log(" (myshdr.vsh -> myshdr.metal).");
log(" -vx \"fileExtns\" - List of GLSL vertex shader file extensions.");
log(" May be omitted for defaults (\"vs vsh vert vertex\").");
log(" -tcx \"fileExtns\" - List of GLSL tessellation control shader file extensions.");
log(" May be omitted for defaults (\"tcs tcsh tesc\").");
log(" -tex \"fileExtns\" - List of GLSL tessellation evaluation shader file extensions.");
log(" May be omitted for defaults (\"tes tesh tese\").");
log(" -fx \"fileExtns\" - List of GLSL fragment shader file extensions.");
log(" May be omitted for defaults (\"fs fsh frag fragment\").");
log(" -cx \"fileExtns\" - List of GLSL compute shader file extensions.");
@ -386,6 +400,8 @@ void MoltenVKShaderConverterTool::reportPerformance(MVKPerformanceTracker& shade
MoltenVKShaderConverterTool::MoltenVKShaderConverterTool(int argc, const char* argv[]) {
extractTokens(_defaultVertexShaderExtns, _glslVtxFileExtns);
extractTokens(_defaultTescShaderExtns, _glslTescFileExtns);
extractTokens(_defaultTeseShaderExtns, _glslTeseFileExtns);
extractTokens(_defaultFragShaderExtns, _glslFragFileExtns);
extractTokens(_defaultCompShaderExtns, _glslCompFileExtns);
extractTokens(_defaultSPIRVShaderExtns, _spvFileExtns);
@ -405,7 +421,7 @@ MoltenVKShaderConverterTool::MoltenVKShaderConverterTool(int argc, const char* a
_quietMode = false;
_mslVersionMajor = 2;
_mslVersionMinor = 2;
_mslVersionMinor = 4;
_mslVersionPatch = 0;
_mslPlatform = SPIRVToMSLConversionOptions().mslOptions.platform;
@ -553,6 +569,24 @@ bool MoltenVKShaderConverterTool::parseArgs(int argc, const char* argv[]) {
continue;
}
if (equal(arg, "-tcx", true)) {
int optIdx = argIdx;
string shdrExtnStr;
argIdx = optionalParam(shdrExtnStr, argIdx, argc, argv);
if (argIdx == optIdx || shdrExtnStr.length() == 0) { return false; }
extractTokens(shdrExtnStr, _glslTescFileExtns);
continue;
}
if (equal(arg, "-tex", true)) {
int optIdx = argIdx;
string shdrExtnStr;
argIdx = optionalParam(shdrExtnStr, argIdx, argc, argv);
if (argIdx == optIdx || shdrExtnStr.length() == 0) { return false; }
extractTokens(shdrExtnStr, _glslTeseFileExtns);
continue;
}
if (equal(arg, "-fx", true)) {
int optIdx = argIdx;
string shdrExtnStr;

View File

@ -98,6 +98,8 @@ namespace mvk {
std::string _hdrOutVarName;
std::string _origPathExtnSep;
std::vector<std::string> _glslVtxFileExtns;
std::vector<std::string> _glslTescFileExtns;
std::vector<std::string> _glslTeseFileExtns;
std::vector<std::string> _glslFragFileExtns;
std::vector<std::string> _glslCompFileExtns;
std::vector<std::string> _spvFileExtns;

View File

@ -100,12 +100,18 @@ bool mvk::compile(const string& mslSourceCode,
}
@autoreleasepool {
NSArray* mtlDevs = [MTLCopyAllDevices() autorelease];
if (mtlDevs.count == 0) {
errMsg = "Could not retrieve MTLDevice to compile shader.";
return false;
}
MTLCompileOptions* mtlCompileOptions = [[MTLCompileOptions new] autorelease];
mtlCompileOptions.languageVersion = mslVerEnum;
NSError* err = nil;
id<MTLLibrary> mtlLib = [[MTLCreateSystemDefaultDevice() newLibraryWithSource: @(mslSourceCode.c_str())
options: mtlCompileOptions
error: &err] autorelease];
id<MTLLibrary> mtlLib = [[mtlDevs[0] newLibraryWithSource: @(mslSourceCode.c_str())
options: mtlCompileOptions
error: &err] autorelease];
errMsg = err ? [NSString stringWithFormat: @"(Error code %li):\n%@", (long)err.code, err.localizedDescription].UTF8String : "";
return !!mtlLib;
}