in Source/Core/ShaderConductor.cpp [683:943]
Compiler::ResultDesc CrossCompile(const Compiler::ResultDesc& binaryResult, const Compiler::SourceDesc& source,
const Compiler::Options& options, const Compiler::TargetDesc& target)
{
assert((target.language != ShadingLanguage::Dxil) && (target.language != ShadingLanguage::SpirV));
assert((binaryResult.target.Size() & (sizeof(uint32_t) - 1)) == 0);
Compiler::ResultDesc ret;
ret.errorWarningMsg = binaryResult.errorWarningMsg;
ret.isText = true;
uint32_t intVersion = 0;
if (target.version != nullptr)
{
intVersion = std::stoi(target.version);
}
const uint32_t* spirvIr = reinterpret_cast<const uint32_t*>(binaryResult.target.Data());
const size_t spirvSize = binaryResult.target.Size() / sizeof(uint32_t);
std::unique_ptr<spirv_cross::CompilerGLSL> compiler;
bool combinedImageSamplers = false;
bool buildDummySampler = false;
switch (target.language)
{
case ShadingLanguage::Hlsl:
if ((source.stage == ShaderStage::GeometryShader) || (source.stage == ShaderStage::HullShader) ||
(source.stage == ShaderStage::DomainShader))
{
// Check https://github.com/KhronosGroup/SPIRV-Cross/issues/121 for details
AppendError(ret, "GS, HS, and DS has not been supported yet.");
return ret;
}
if ((source.stage == ShaderStage::GeometryShader) && (intVersion < 40))
{
AppendError(ret, "HLSL shader model earlier than 4.0 doesn't have GS or CS.");
return ret;
}
if ((source.stage == ShaderStage::ComputeShader) && (intVersion < 50))
{
AppendError(ret, "CS in HLSL shader model earlier than 5.0 is not supported.");
return ret;
}
if (((source.stage == ShaderStage::HullShader) || (source.stage == ShaderStage::DomainShader)) && (intVersion < 50))
{
AppendError(ret, "HLSL shader model earlier than 5.0 doesn't have HS or DS.");
return ret;
}
compiler = std::make_unique<spirv_cross::CompilerHLSL>(spirvIr, spirvSize);
break;
case ShadingLanguage::Glsl:
case ShadingLanguage::Essl:
compiler = std::make_unique<spirv_cross::CompilerGLSL>(spirvIr, spirvSize);
combinedImageSamplers = true;
buildDummySampler = true;
// Legacy GLSL fixups
if (intVersion <= 300)
{
auto vars = compiler->get_active_interface_variables();
for (auto& var : vars)
{
auto varClass = compiler->get_storage_class(var);
// Make VS out and PS in variable names match
if ((source.stage == ShaderStage::VertexShader) && (varClass == spv::StorageClass::StorageClassOutput))
{
auto name = compiler->get_name(var);
if ((name.find("out_var_") == 0) || (name.find("out.var.") == 0))
{
name.replace(0, 8, "varying_");
compiler->set_name(var, name);
}
}
else if ((source.stage == ShaderStage::PixelShader) && (varClass == spv::StorageClass::StorageClassInput))
{
auto name = compiler->get_name(var);
if ((name.find("in_var_") == 0) || (name.find("in.var.") == 0))
{
name.replace(0, 7, "varying_");
compiler->set_name(var, name);
}
}
}
}
break;
case ShadingLanguage::Msl_macOS:
case ShadingLanguage::Msl_iOS:
if (source.stage == ShaderStage::GeometryShader)
{
AppendError(ret, "MSL doesn't have GS.");
return ret;
}
compiler = std::make_unique<spirv_cross::CompilerMSL>(spirvIr, spirvSize);
break;
default:
llvm_unreachable("Invalid target language.");
}
spv::ExecutionModel model;
switch (source.stage)
{
case ShaderStage::VertexShader:
model = spv::ExecutionModelVertex;
break;
case ShaderStage::HullShader:
model = spv::ExecutionModelTessellationControl;
break;
case ShaderStage::DomainShader:
model = spv::ExecutionModelTessellationEvaluation;
break;
case ShaderStage::GeometryShader:
model = spv::ExecutionModelGeometry;
break;
case ShaderStage::PixelShader:
model = spv::ExecutionModelFragment;
break;
case ShaderStage::ComputeShader:
model = spv::ExecutionModelGLCompute;
break;
default:
llvm_unreachable("Invalid shader stage.");
}
compiler->set_entry_point(source.entryPoint, model);
spirv_cross::CompilerGLSL::Options opts = compiler->get_common_options();
if (target.version != nullptr)
{
opts.version = intVersion;
}
opts.es = (target.language == ShadingLanguage::Essl);
opts.force_temporary = false;
opts.separate_shader_objects = true;
opts.flatten_multidimensional_arrays = false;
opts.enable_420pack_extension =
(target.language == ShadingLanguage::Glsl) && ((target.version == nullptr) || (opts.version >= 420));
opts.vulkan_semantics = false;
opts.vertex.fixup_clipspace = false;
opts.vertex.flip_vert_y = false;
opts.vertex.support_nonzero_base_instance = true;
compiler->set_common_options(opts);
if (target.language == ShadingLanguage::Hlsl)
{
auto* hlslCompiler = static_cast<spirv_cross::CompilerHLSL*>(compiler.get());
auto hlslOpts = hlslCompiler->get_hlsl_options();
if (target.version != nullptr)
{
if (opts.version < 30)
{
AppendError(ret, "HLSL shader model earlier than 3.0 is not supported.");
return ret;
}
hlslOpts.shader_model = opts.version;
}
if (hlslOpts.shader_model <= 30)
{
combinedImageSamplers = true;
buildDummySampler = true;
}
hlslCompiler->set_hlsl_options(hlslOpts);
}
else if ((target.language == ShadingLanguage::Msl_macOS) || (target.language == ShadingLanguage::Msl_iOS))
{
auto* mslCompiler = static_cast<spirv_cross::CompilerMSL*>(compiler.get());
auto mslOpts = mslCompiler->get_msl_options();
if (target.version != nullptr)
{
mslOpts.msl_version = opts.version;
}
mslOpts.swizzle_texture_samples = false;
mslOpts.platform = (target.language == ShadingLanguage::Msl_iOS) ? spirv_cross::CompilerMSL::Options::iOS
: spirv_cross::CompilerMSL::Options::macOS;
mslCompiler->set_msl_options(mslOpts);
const auto& resources = mslCompiler->get_shader_resources();
uint32_t textureBinding = 0;
for (const auto& image : resources.separate_images)
{
mslCompiler->set_decoration(image.id, spv::DecorationBinding, textureBinding);
++textureBinding;
}
uint32_t samplerBinding = 0;
for (const auto& sampler : resources.separate_samplers)
{
mslCompiler->set_decoration(sampler.id, spv::DecorationBinding, samplerBinding);
++samplerBinding;
}
}
if (buildDummySampler)
{
const uint32_t sampler = compiler->build_dummy_sampler_for_combined_images();
if (sampler != 0)
{
compiler->set_decoration(sampler, spv::DecorationDescriptorSet, 0);
compiler->set_decoration(sampler, spv::DecorationBinding, 0);
}
}
if (combinedImageSamplers)
{
compiler->build_combined_image_samplers();
if (options.inheritCombinedSamplerBindings)
{
spirv_cross_util::inherit_combined_sampler_bindings(*compiler);
}
for (auto& remap : compiler->get_combined_image_samplers())
{
compiler->set_name(remap.combined_id,
"SPIRV_Cross_Combined" + compiler->get_name(remap.image_id) + compiler->get_name(remap.sampler_id));
}
}
if (target.language == ShadingLanguage::Hlsl)
{
auto* hlslCompiler = static_cast<spirv_cross::CompilerHLSL*>(compiler.get());
const uint32_t newBuiltin = hlslCompiler->remap_num_workgroups_builtin();
if (newBuiltin)
{
compiler->set_decoration(newBuiltin, spv::DecorationDescriptorSet, 0);
compiler->set_decoration(newBuiltin, spv::DecorationBinding, 0);
}
}
try
{
const std::string targetStr = compiler->compile();
ret.target.Reset(targetStr.data(), static_cast<uint32_t>(targetStr.size()));
ret.hasError = false;
ret.reflection.descs.Reset(binaryResult.reflection.descs.Data(),
sizeof(Compiler::ReflectionDesc) * binaryResult.reflection.descCount);
ret.reflection.descCount = binaryResult.reflection.descCount;
ret.reflection.instructionCount = binaryResult.reflection.instructionCount;
}
catch (spirv_cross::CompilerError& error)
{
const char* errorMsg = error.what();
ret.errorWarningMsg.Reset(errorMsg, static_cast<uint32_t>(std::strlen(errorMsg)));
ret.hasError = true;
}
return ret;
}