diff --git a/tools/shaderc/shaderc.cpp b/tools/shaderc/shaderc.cpp index 56370045b..c99a5e4e5 100644 --- a/tools/shaderc/shaderc.cpp +++ b/tools/shaderc/shaderc.cpp @@ -150,6 +150,77 @@ namespace bgfx }; BX_STATIC_ASSERT(BX_COUNTOF(s_uniformTypeName) == UniformType::Count*2); + + Options::Options() + : shaderType(' ') + , disasm(false) + , raw(false) + , preprocessOnly(false) + , depends(false) + , debugInformation(false) + , avoidFlowControl(false) + , noPreshader(false) + , partialPrecision(false) + , preferFlowControl(false) + , backwardsCompatibility(false) + , warningsAreErrors(false) + , optimize(false) + , optimizationLevel(3) + { + } + + void Options::dump() + { + BX_TRACE("Options:\n" + "\t shaderType: %c\n" + "\t platform: %s\n" + "\t profile: %s\n" + "\t inputFile: %s\n" + "\t outputFile: %s\n" + "\t disasm: %s\n" + "\t raw: %s\n" + "\t preprocessOnly: %s\n" + "\t depends: %s\n" + "\t debugInformation: %s\n" + "\t avoidFlowControl: %s\n" + "\t noPreshader: %s\n" + "\t partialPrecision: %s\n" + "\t preferFlowControl: %s\n" + "\t backwardsCompatibility: %s\n" + "\t warningsAreErrors: %s\n" + "\t optimize: %s\n" + "\t optimizationLevel: %d\n" + + , shaderType + , platform.c_str() + , profile.c_str() + , inputFilePath.c_str() + , outputFilePath.c_str() + , disasm ? "true" : "false" + , raw ? "true" : "false" + , preprocessOnly ? "true" : "false" + , depends ? "true" : "false" + , debugInformation ? "true" : "false" + , avoidFlowControl ? "true" : "false" + , noPreshader ? "true" : "false" + , partialPrecision ? "true" : "false" + , preferFlowControl ? "true" : "false" + , backwardsCompatibility ? "true" : "false" + , warningsAreErrors ? "true" : "false" + , optimize ? "true" : "false" + , optimizationLevel + ); + + for(size_t i=0; i(nl); + + if (0 == bx::strCmp(str, "input", 5) ) + { + str += 5; + const char* comment = bx::strFind(str, "//"); + eol = NULL != comment && comment < eol ? comment : eol; + inputHash = parseInOut(shaderInputs, str, eol); + } + else if (0 == bx::strCmp(str, "output", 6) ) + { + str += 6; + const char* comment = bx::strFind(str, "//"); + eol = NULL != comment && comment < eol ? comment : eol; + outputHash = parseInOut(shaderOutputs, str, eol); + } + else if (0 == bx::strCmp(str, "raw", 3) ) + { + raw = true; + str += 3; + } + + input = const_cast(bx::strws(input) ); + } + } + + if (raw) + { + if ('f' == _options.shaderType) + { + bx::write(_writer, BGFX_CHUNK_MAGIC_FSH); + bx::write(_writer, inputHash); + } + else if ('v' == _options.shaderType) + { + bx::write(_writer, BGFX_CHUNK_MAGIC_VSH); + bx::write(_writer, outputHash); + } + else + { + bx::write(_writer, BGFX_CHUNK_MAGIC_CSH); + bx::write(_writer, outputHash); + } + + if (0 != glsl) + { + bx::write(_writer, uint16_t(0) ); + + uint32_t shaderSize = (uint32_t)bx::strLen(input); + bx::write(_writer, shaderSize); + bx::write(_writer, input, shaderSize); + bx::write(_writer, uint8_t(0) ); + + compiled = true; + } + else if (0 != pssl) + { + compiled = compilePSSLShader(_options, 0, input, _writer); + } + else + { + compiled = compileHLSLShader(_options, d3d, input, _writer); + } + } + else if ('c' == _options.shaderType) // Compute + { + char* entry = const_cast(bx::strFind(input, "void main()") ); + if (NULL == entry) + { + fprintf(stderr, "Shader entry point 'void main()' is not found.\n"); + } + else + { + if (0 != glsl + || 0 != essl + || 0 != metal) + { + } + else + { + preprocessor.writef( + "#define lowp\n" + "#define mediump\n" + "#define highp\n" + "#define ivec2 int2\n" + "#define ivec3 int3\n" + "#define ivec4 int4\n" + "#define uvec2 uint2\n" + "#define uvec3 uint3\n" + "#define uvec4 uint4\n" + "#define vec2 float2\n" + "#define vec3 float3\n" + "#define vec4 float4\n" + "#define mat2 float2x2\n" + "#define mat3 float3x3\n" + "#define mat4 float4x4\n" + ); + + entry[4] = '_'; + + preprocessor.writef("#define void_main()"); + preprocessor.writef(" \\\n\tvoid main("); + + uint32_t arg = 0; + + const bool hasLocalInvocationID = NULL != bx::strFind(input, "gl_LocalInvocationID"); + const bool hasLocalInvocationIndex = NULL != bx::strFind(input, "gl_LocalInvocationIndex"); + const bool hasGlobalInvocationID = NULL != bx::strFind(input, "gl_GlobalInvocationID"); + const bool hasWorkGroupID = NULL != bx::strFind(input, "gl_WorkGroupID"); + + if (hasLocalInvocationID) + { + preprocessor.writef( + " \\\n\t%sint3 gl_LocalInvocationID : SV_GroupThreadID" + , arg++ > 0 ? ", " : " " + ); + } + + if (hasLocalInvocationIndex) + { + preprocessor.writef( + " \\\n\t%sint gl_LocalInvocationIndex : SV_GroupIndex" + , arg++ > 0 ? ", " : " " + ); + } + + if (hasGlobalInvocationID) + { + preprocessor.writef( + " \\\n\t%sint3 gl_GlobalInvocationID : SV_DispatchThreadID" + , arg++ > 0 ? ", " : " " + ); + } + + if (hasWorkGroupID) + { + preprocessor.writef( + " \\\n\t%sint3 gl_WorkGroupID : SV_GroupID" + , arg++ > 0 ? ", " : " " + ); + } + + preprocessor.writef( + " \\\n\t)\n" + ); + } + + if (preprocessor.run(input) ) + { + //BX_TRACE("Input file: %s", filePath); + //BX_TRACE("Output file: %s", outFilePath); + + if (_options.preprocessOnly) + { + bx::write(_writer, preprocessor.m_preprocessed.c_str(), (int32_t)preprocessor.m_preprocessed.size() ); + + return true; + } + + { + bx::write(_writer, BGFX_CHUNK_MAGIC_CSH); + bx::write(_writer, outputHash); + + if (0 != glsl + || 0 != essl) + { + std::string code; + + if (essl) + { + bx::stringPrintf(code, "#version 310 es\n"); + } + else + { + bx::stringPrintf(code, "#version %d\n", glsl == 0 ? 430 : glsl); + } + + code += preprocessor.m_preprocessed; +#if 1 + bx::write(_writer, uint16_t(0) ); + + uint32_t shaderSize = (uint32_t)code.size(); + bx::write(_writer, shaderSize); + bx::write(_writer, code.c_str(), shaderSize); + bx::write(_writer, uint8_t(0) ); + + compiled = true; +#else + compiled = compileGLSLShader(cmdLine, essl, code, writer); +#endif // 0 + } + else if (0 != spirv) + { + compiled = compileSPIRVShader(_options, 0, preprocessor.m_preprocessed, _writer); + } + else if (0 != pssl) + { + compiled = compilePSSLShader(_options, 0, preprocessor.m_preprocessed, _writer); + } + else + { + compiled = compileHLSLShader(_options, d3d, preprocessor.m_preprocessed, _writer); + } + } + + if (compiled) + { + if (_options.depends) + { + std::string ofp = _options.outputFilePath; + ofp += ".d"; + bx::FileWriter writer; + if (bx::open(&writer, ofp.c_str() ) ) + { + writef(&writer, "%s : %s\n", _options.outputFilePath.c_str(), preprocessor.m_depends.c_str() ); + bx::close(&writer); + } + } + } + } + } + } + else // Vertex/Fragment + { + char* entry = const_cast(bx::strFind(input, "void main()") ); + if (NULL == entry) + { + fprintf(stderr, "Shader entry point 'void main()' is not found.\n"); + } + else + { + if (0 != glsl + || 0 != essl + || 0 != metal) + { + if (0 == essl) + { + // bgfx shadow2D/Proj behave like EXT_shadow_samplers + // not as GLSL language 1.2 specs shadow2D/Proj. + preprocessor.writef( + "#define shadow2D(_sampler, _coord) bgfxShadow2D(_sampler, _coord).x\n" + "#define shadow2DProj(_sampler, _coord) bgfxShadow2DProj(_sampler, _coord).x\n" + ); + } + + for (InOut::const_iterator it = shaderInputs.begin(), itEnd = shaderInputs.end(); it != itEnd; ++it) + { + VaryingMap::const_iterator varyingIt = varyingMap.find(*it); + if (varyingIt != varyingMap.end() ) + { + const Varying& var = varyingIt->second; + const char* name = var.m_name.c_str(); + + if (0 == bx::strCmp(name, "a_", 2) + || 0 == bx::strCmp(name, "i_", 2) ) + { + preprocessor.writef("attribute %s %s %s %s;\n" + , var.m_precision.c_str() + , var.m_interpolation.c_str() + , var.m_type.c_str() + , name + ); + } + else + { + preprocessor.writef("%s varying %s %s %s;\n" + , var.m_interpolation.c_str() + , var.m_precision.c_str() + , var.m_type.c_str() + , name + ); + } + } + } + + for (InOut::const_iterator it = shaderOutputs.begin(), itEnd = shaderOutputs.end(); it != itEnd; ++it) + { + VaryingMap::const_iterator varyingIt = varyingMap.find(*it); + if (varyingIt != varyingMap.end() ) + { + const Varying& var = varyingIt->second; + preprocessor.writef("%s varying %s %s;\n" + , var.m_interpolation.c_str() + , var.m_type.c_str() + , var.m_name.c_str() + ); + } + } + } + else + { + preprocessor.writef( + "#define lowp\n" + "#define mediump\n" + "#define highp\n" + "#define ivec2 int2\n" + "#define ivec3 int3\n" + "#define ivec4 int4\n" + "#define uvec2 uint2\n" + "#define uvec3 uint3\n" + "#define uvec4 uint4\n" + "#define vec2 float2\n" + "#define vec3 float3\n" + "#define vec4 float4\n" + "#define mat2 float2x2\n" + "#define mat3 float3x3\n" + "#define mat4 float4x4\n" + ); + + if (hlsl != 0 + && hlsl < 4) + { + preprocessor.writef( + "#define centroid\n" + "#define flat\n" + "#define noperspective\n" + "#define smooth\n" + ); + } + + entry[4] = '_'; + + if ('f' == _options.shaderType) + { + const char* insert = bx::strFind(entry, "{"); + if (NULL != insert) + { + insert = strInsert(const_cast(insert+1), "\nvec4 bgfx_VoidFrag = vec4_splat(0.0);\n"); + } + + const bool hasFragColor = NULL != bx::strFind(input, "gl_FragColor"); + const bool hasFragCoord = NULL != bx::strFind(input, "gl_FragCoord") || hlsl > 3 || hlsl == 2; + const bool hasFragDepth = NULL != bx::strFind(input, "gl_FragDepth"); + const bool hasFrontFacing = NULL != bx::strFind(input, "gl_FrontFacing"); + const bool hasPrimitiveId = NULL != bx::strFind(input, "gl_PrimitiveID"); + + bool hasFragData[8] = {}; + uint32_t numFragData = 0; + for (uint32_t ii = 0; ii < BX_COUNTOF(hasFragData); ++ii) + { + char temp[32]; + bx::snprintf(temp, BX_COUNTOF(temp), "gl_FragData[%d]", ii); + hasFragData[ii] = NULL != bx::strFind(input, temp); + numFragData += hasFragData[ii]; + } + + if (0 == numFragData) + { + // GL errors when both gl_FragColor and gl_FragData is used. + // This will trigger the same error with HLSL compiler too. + preprocessor.writef("#define gl_FragColor gl_FragData_0_\n"); + + // If it has gl_FragData or gl_FragColor, color target at + // index 0 exists, otherwise shader is not modifying color + // targets. + hasFragData[0] |= hasFragColor || d3d < 11; + + if (NULL != insert + && d3d < 11 + && !hasFragColor) + { + insert = strInsert(const_cast(insert+1), "\ngl_FragColor = bgfx_VoidFrag;\n"); + } + } + + preprocessor.writef("#define void_main()"); + preprocessor.writef(" \\\n\tvoid main("); + + uint32_t arg = 0; + + if (hasFragCoord) + { + preprocessor.writef(" \\\n\tvec4 gl_FragCoord : SV_POSITION"); + ++arg; + } + + for (InOut::const_iterator it = shaderInputs.begin(), itEnd = shaderInputs.end(); it != itEnd; ++it) + { + VaryingMap::const_iterator varyingIt = varyingMap.find(*it); + if (varyingIt != varyingMap.end() ) + { + const Varying& var = varyingIt->second; + preprocessor.writef(" \\\n\t%s%s %s %s : %s" + , arg++ > 0 ? ", " : " " + , interpolationDx11(var.m_interpolation.c_str() ) + , var.m_type.c_str() + , var.m_name.c_str() + , var.m_semantics.c_str() + ); + } + } + + const uint32_t maxRT = d3d > 9 ? BX_COUNTOF(hasFragData) : 4; + + for (uint32_t ii = 0; ii < BX_COUNTOF(hasFragData); ++ii) + { + if (ii < maxRT) + { + if (hasFragData[ii]) + { + addFragData(preprocessor, input, ii, arg++ > 0); + } + } + else + { + voidFragData(input, ii); + } + } + + if (hasFragDepth) + { + preprocessor.writef( + " \\\n\t%sout float gl_FragDepth : SV_DEPTH" + , arg++ > 0 ? ", " : " " + ); + } + + if (hasFrontFacing + && hlsl >= 3) + { + preprocessor.writef( + " \\\n\t%sfloat __vface : VFACE" + , arg++ > 0 ? ", " : " " + ); + } + + if (hasPrimitiveId) + { + if (d3d > 9) + { + preprocessor.writef( + " \\\n\t%suint gl_PrimitiveID : SV_PrimitiveID" + , arg++ > 0 ? ", " : " " + ); + } + else + { + fprintf(stderr, "gl_PrimitiveID builtin is not supported by this D3D9 HLSL.\n"); + return false; + } + } + + preprocessor.writef( + " \\\n\t)\n" + ); + + if (hasFrontFacing) + { + if (hlsl >= 3) + { + preprocessor.writef( + "#define gl_FrontFacing (__vface <= 0.0)\n" + ); + } + else + { + preprocessor.writef( + "#define gl_FrontFacing false\n" + ); + } + } + } + else if ('v' == _options.shaderType) + { + const bool hasVertexId = NULL != bx::strFind(input, "gl_VertexID"); + const bool hasInstanceId = NULL != bx::strFind(input, "gl_InstanceID"); + + const char* brace = bx::strFind(entry, "{"); + if (NULL != brace) + { + const char* end = bx::strmb(brace, '{', '}'); + if (NULL != end) + { + strInsert(const_cast(end), "__RETURN__;\n"); + } + } + + preprocessor.writef( + "struct Output\n" + "{\n" + "\tvec4 gl_Position : SV_POSITION;\n" + "#define gl_Position _varying_.gl_Position\n" + ); + for (InOut::const_iterator it = shaderOutputs.begin(), itEnd = shaderOutputs.end(); it != itEnd; ++it) + { + VaryingMap::const_iterator varyingIt = varyingMap.find(*it); + if (varyingIt != varyingMap.end() ) + { + const Varying& var = varyingIt->second; + preprocessor.writef("\t%s %s : %s;\n", var.m_type.c_str(), var.m_name.c_str(), var.m_semantics.c_str() ); + preprocessor.writef("#define %s _varying_.%s\n", var.m_name.c_str(), var.m_name.c_str() ); + } + } + preprocessor.writef( + "};\n" + ); + + preprocessor.writef("#define void_main() \\\n"); + preprocessor.writef("Output main("); + uint32_t arg = 0; + for (InOut::const_iterator it = shaderInputs.begin(), itEnd = shaderInputs.end(); it != itEnd; ++it) + { + VaryingMap::const_iterator varyingIt = varyingMap.find(*it); + if (varyingIt != varyingMap.end() ) + { + const Varying& var = varyingIt->second; + preprocessor.writef( + " \\\n\t%s%s %s : %s" + , arg++ > 0 ? ", " : "" + , var.m_type.c_str() + , var.m_name.c_str() + , var.m_semantics.c_str() + ); + } + } + + if (hasVertexId) + { + if (d3d > 9) + { + preprocessor.writef( + " \\\n\t%suint gl_VertexID : SV_VertexID" + , arg++ > 0 ? ", " : " " + ); + } + else + { + fprintf(stderr, "gl_VertexID builtin is not supported by this D3D9 HLSL.\n"); + return false; + } + } + + if (hasInstanceId) + { + if (d3d > 9) + { + preprocessor.writef( + " \\\n\t%suint gl_InstanceID : SV_InstanceID" + , arg++ > 0 ? ", " : " " + ); + } + else + { + fprintf(stderr, "gl_InstanceID builtin is not supported by this D3D9 HLSL.\n"); + return false; + } + } + + preprocessor.writef( + ") \\\n" + "{ \\\n" + "\tOutput _varying_;" + ); + + for (InOut::const_iterator it = shaderOutputs.begin(), itEnd = shaderOutputs.end(); it != itEnd; ++it) + { + VaryingMap::const_iterator varyingIt = varyingMap.find(*it); + if (varyingIt != varyingMap.end() ) + { + const Varying& var = varyingIt->second; + preprocessor.writef(" \\\n\t%s", var.m_name.c_str() ); + if (!var.m_init.empty() ) + { + preprocessor.writef(" = %s", var.m_init.c_str() ); + } + preprocessor.writef(";"); + } + } + + preprocessor.writef( + "\n#define __RETURN__ \\\n" + "\t} \\\n" + ); + + if (hlsl != 0 + && hlsl <= 3) + { +// preprocessor.writef( +// "\tgl_Position.xy += u_viewTexel.xy * gl_Position.w; \\\n" +// ); + } + + preprocessor.writef( + "\treturn _varying_" + ); + } + } + + if (preprocessor.run(input) ) + { + //BX_TRACE("Input file: %s", filePath); + //BX_TRACE("Output file: %s", outFilePath); + + if (_options.preprocessOnly) + { + if (0 != glsl) + { + if (essl != 0) + { + writef(_writer + , "#ifdef GL_ES\n" + "precision highp float;\n" + "#endif // GL_ES\n\n" + ); + } + } + bx::write(_writer, preprocessor.m_preprocessed.c_str(), (int32_t)preprocessor.m_preprocessed.size() ); + + return true; + } + + { + if ('f' == _options.shaderType) + { + bx::write(_writer, BGFX_CHUNK_MAGIC_FSH); + bx::write(_writer, inputHash); + } + else if ('v' == _options.shaderType) + { + bx::write(_writer, BGFX_CHUNK_MAGIC_VSH); + bx::write(_writer, outputHash); + } + else + { + bx::write(_writer, BGFX_CHUNK_MAGIC_CSH); + bx::write(_writer, outputHash); + } + + if (0 != glsl + || 0 != essl + || 0 != metal) + { + std::string code; + + if (glsl < 400) + { + const bool usesTextureLod = false + || !!bx::findIdentifierMatch(input, s_ARB_shader_texture_lod) + || !!bx::findIdentifierMatch(input, s_EXT_shader_texture_lod) + ; + const bool usesInstanceID = !!bx::strFind(input, "gl_InstanceID"); + const bool usesGpuShader4 = !!bx::findIdentifierMatch(input, s_EXT_gpu_shader4); + const bool usesGpuShader5 = !!bx::findIdentifierMatch(input, s_ARB_gpu_shader5); + const bool usesTexelFetch = !!bx::findIdentifierMatch(input, s_texelFetch); + const bool usesTextureMS = !!bx::findIdentifierMatch(input, s_ARB_texture_multisample); + const bool usesTextureArray = !!bx::findIdentifierMatch(input, s_textureArray); + const bool usesPacking = !!bx::findIdentifierMatch(input, s_ARB_shading_language_packing); + + if (0 == essl) + { + const bool need130 = 120 == glsl && (false + || bx::findIdentifierMatch(input, s_130) + || usesTexelFetch + ); + + if (0 != metal) + { + bx::stringPrintf(code, "#version 120\n"); + } + else + { + bx::stringPrintf(code, "#version %s\n", need130 ? "130" : _options.profile.c_str()); + glsl = 130; + } + + if (usesInstanceID) + { + bx::stringPrintf(code + , "#extension GL_ARB_draw_instanced : enable\n" + ); + } + + if (usesGpuShader4) + { + bx::stringPrintf(code + , "#extension GL_EXT_gpu_shader4 : enable\n" + ); + } + + if (usesGpuShader5) + { + bx::stringPrintf(code + , "#extension GL_ARB_gpu_shader5 : enable\n" + ); + } + + if (usesPacking) + { + bx::stringPrintf(code + , "#extension GL_ARB_shading_language_packing : enable\n" + ); + } + + bool ARB_shader_texture_lod = false; + bool EXT_shader_texture_lod = false; + + if (usesTextureLod) + { + if ('f' == _options.shaderType) + { + ARB_shader_texture_lod = true; + bx::stringPrintf(code + , "#extension GL_ARB_shader_texture_lod : enable\n" + ); + } + else + { + EXT_shader_texture_lod = true; + bx::stringPrintf(code + , "#extension GL_EXT_shader_texture_lod : enable\n" + ); + } + } + + if (usesTextureMS) + { + bx::stringPrintf(code + , "#extension GL_ARB_texture_multisample : enable\n" + ); + } + + if (usesTextureArray) + { + bx::stringPrintf(code + , "#extension GL_EXT_texture_array : enable\n" + ); + } + + if (130 > glsl) + { + bx::stringPrintf(code, + "#define ivec2 vec2\n" + "#define ivec3 vec3\n" + "#define ivec4 vec4\n" + ); + } + + if (ARB_shader_texture_lod) + { + bx::stringPrintf(code, + "#define texture2DProjLod texture2DProjLodARB\n" + "#define texture2DGrad texture2DGradARB\n" + "#define texture2DProjGrad texture2DProjGradARB\n" + "#define textureCubeGrad textureCubeGradARB\n" + ); + } + else if (EXT_shader_texture_lod) + { + bx::stringPrintf(code, + "#define texture2DProjLod texture2DProjLodEXT\n" + "#define texture2DGrad texture2DGradEXT\n" + "#define texture2DProjGrad texture2DProjGradEXT\n" + "#define textureCubeGrad textureCubeGradEXT\n" + ); + } + + if (need130) + { + bx::stringPrintf(code + , "#define bgfxShadow2D(_sampler, _coord) vec4_splat(texture(_sampler, _coord))\n" + "#define bgfxShadow2DProj(_sampler, _coord) vec4_splat(textureProj(_sampler, _coord))\n" + ); + } + else + { + bx::stringPrintf(code + , "#define bgfxShadow2D shadow2D\n" + "#define bgfxShadow2DProj shadow2DProj\n" + ); + } + } + else + { + // Pretend that all extensions are available. + // This will be stripped later. + if (usesTextureLod) + { + bx::stringPrintf(code + , "#extension GL_EXT_shader_texture_lod : enable\n" + "#define texture2DLod texture2DLodEXT\n" + "#define texture2DGrad texture2DGradEXT\n" + "#define texture2DProjLod texture2DProjLodEXT\n" + "#define texture2DProjGrad texture2DProjGradEXT\n" + "#define textureCubeLod textureCubeLodEXT\n" + "#define textureCubeGrad textureCubeGradEXT\n" + ); + } + + if (NULL != bx::findIdentifierMatch(input, s_OES_standard_derivatives) ) + { + bx::stringPrintf(code, "#extension GL_OES_standard_derivatives : enable\n"); + } + + if (NULL != bx::findIdentifierMatch(input, s_OES_texture_3D) ) + { + bx::stringPrintf(code, "#extension GL_OES_texture_3D : enable\n"); + } + + if (NULL != bx::findIdentifierMatch(input, s_EXT_shadow_samplers) ) + { + bx::stringPrintf(code + , "#extension GL_EXT_shadow_samplers : enable\n" + "#define shadow2D shadow2DEXT\n" + "#define shadow2DProj shadow2DProjEXT\n" + ); + } + + if (usesGpuShader5) + { + bx::stringPrintf(code + , "#extension GL_ARB_gpu_shader5 : enable\n" + ); + } + + if (usesPacking) + { + bx::stringPrintf(code + , "#extension GL_ARB_shading_language_packing : enable\n" + ); + } + + if (NULL != bx::findIdentifierMatch(input, "gl_FragDepth") ) + { + bx::stringPrintf(code + , "#extension GL_EXT_frag_depth : enable\n" + "#define gl_FragDepth gl_FragDepthEXT\n" + ); + } + + if (usesTextureArray) + { + bx::stringPrintf(code + , "#extension GL_EXT_texture_array : enable\n" + ); + } + + bx::stringPrintf(code, + "#define ivec2 vec2\n" + "#define ivec3 vec3\n" + "#define ivec4 vec4\n" + ); + } + } + else + { + bx::stringPrintf(code, "#version %d\n", glsl); + } + + code += preprocessor.m_preprocessed; + + if (glsl > 400) + { + bx::write(_writer, uint16_t(0) ); + + uint32_t shaderSize = (uint32_t)code.size(); + bx::write(_writer, shaderSize); + bx::write(_writer, code.c_str(), shaderSize); + bx::write(_writer, uint8_t(0) ); + + compiled = true; + } + else + { + compiled = compileGLSLShader(_options + , metal ? BX_MAKEFOURCC('M', 'T', 'L', 0) : essl + , code + , _writer + ); + } + } + else if (0 != spirv) + { + compiled = compileSPIRVShader(_options + , 0 + , preprocessor.m_preprocessed + , _writer + ); + } + else if (0 != pssl) + { + compiled = compilePSSLShader(_options + , 0 + , preprocessor.m_preprocessed + , _writer + ); + } + else + { + compiled = compileHLSLShader(_options + , d3d + , preprocessor.m_preprocessed + , _writer + ); + } + } + + if (compiled) + { + if (_options.depends) + { + std::string ofp = _options.outputFilePath + ".d"; + bx::FileWriter writer; + if (bx::open(&writer, ofp.c_str() ) ) + { + writef(&writer, "%s : %s\n", _options.outputFilePath.c_str(), preprocessor.m_depends.c_str() ); + bx::close(&writer); + } + } + } + } + } + } + + delete [] data; + + return compiled; + } + + int compileShader(int _argc, const char* _argv[]) + { + bx::CommandLine cmdLine(_argc, _argv); + + if (cmdLine.hasArg('v', "version") ) + { + fprintf(stderr + , "shaderc, bgfx shader compiler tool, version %d.%d.%d.\n" + , BGFX_SHADERC_VERSION_MAJOR + , BGFX_SHADERC_VERSION_MINOR + , BGFX_API_VERSION + ); + return bx::kExitSuccess; + } + + if (cmdLine.hasArg('h', "help") ) + { + help(); return bx::kExitFailure; } + g_verbose = cmdLine.hasArg("verbose"); + + const char* filePath = cmdLine.findOption('f'); + if (NULL == filePath) + { + help("Shader file name must be specified."); + return bx::kExitFailure; + } + + const char* outFilePath = cmdLine.findOption('o'); + if (NULL == outFilePath) + { + help("Output file name must be specified."); + return bx::kExitFailure; + } + + const char* type = cmdLine.findOption('\0', "type"); + if (NULL == type) + { + help("Must specify shader type."); + return bx::kExitFailure; + } + + Options options; + options.inputFilePath = filePath; + options.outputFilePath = outFilePath; + options.shaderType = bx::toLower(type[0]); + + options.disasm = cmdLine.hasArg('\0', "disasm"); + + const char* platform = cmdLine.findOption('\0', "platform"); + if (NULL == platform) + { + platform = ""; + } + + options.platform = platform; + + options.raw = cmdLine.hasArg('\0', "raw"); + + const char* profile = cmdLine.findOption('p', "profile"); + + if ( NULL != profile) + { + options.profile = profile; + } + + { // hlsl only + options.debugInformation = cmdLine.hasArg('\0', "debug"); + options.avoidFlowControl = cmdLine.hasArg('\0', "avoid-flow-control"); + options.noPreshader = cmdLine.hasArg('\0', "no-preshader"); + options.partialPrecision = cmdLine.hasArg('\0', "partial-precision"); + options.preferFlowControl = cmdLine.hasArg('\0', "prefer-flow-control"); + options.backwardsCompatibility = cmdLine.hasArg('\0', "backwards-compatibility"); + options.warningsAreErrors = cmdLine.hasArg('\0', "Werror"); + + uint32_t optimization = 3; + if (cmdLine.hasArg(optimization, 'O') ) + { + options.optimize = true; + options.optimizationLevel = optimization; + } + } + + const char* bin2c = NULL; + if (cmdLine.hasArg("bin2c") ) + { + bin2c = cmdLine.findOption("bin2c"); + if (NULL == bin2c) + { + bin2c = baseName(outFilePath); + uint32_t len = (uint32_t)bx::strLen(bin2c); + char* temp = (char*)alloca(len+1); + for (char *out = temp; *bin2c != '\0';) + { + char ch = *bin2c++; + if (isalnum(ch) ) + { + *out++ = ch; + } + else + { + *out++ = '_'; + } + } + temp[len] = '\0'; + + bin2c = temp; + } + } + + bool depends = cmdLine.hasArg("depends"); + options.preprocessOnly = cmdLine.hasArg("preprocess"); + const char* includeDir = cmdLine.findOption('i'); + + BX_TRACE("depends: %d", depends); + BX_TRACE("preprocessOnly: %d", options.preprocessOnly); + BX_TRACE("includeDir: %s", includeDir); + + for (int ii = 1; NULL != includeDir; ++ii) + { + options.includeDirs.push_back(includeDir); + includeDir = cmdLine.findOption(ii, 'i'); + } + + std::string dir; + { + const char* base = baseName(filePath); + + if (base != filePath) + { + dir.assign(filePath, base-filePath); + options.includeDirs.push_back(dir.c_str()); + } + } + + const char* defines = cmdLine.findOption("define"); + while (NULL != defines + && '\0' != *defines) + { + defines = bx::strws(defines); + const char* eol = bx::strFind(defines, ';'); + if (NULL == eol) + { + eol = defines + bx::strLen(defines); + } + std::string define(defines, eol); + options.defines.push_back(define.c_str() ); + defines = ';' == *eol ? eol+1 : eol; + } + bool compiled = false; bx::FileReader reader; @@ -1070,8 +2227,6 @@ namespace bgfx } else { - VaryingMap varyingMap; - std::string defaultVarying = dir + "varying.def.sc"; const char* varyingdef = cmdLine.findOption("varyingdef", defaultVarying.c_str() ); File attribdef(varyingdef); @@ -1079,1135 +2234,54 @@ namespace bgfx if (NULL != parse && *parse != '\0') { - preprocessor.addDependency(varyingdef); + options.dependencies.push_back(varyingdef); } else { fprintf(stderr, "ERROR: Failed to parse varying def file: \"%s\" No input/output semantics will be generated in the code!\n", varyingdef); } - while (NULL != parse - && *parse != '\0') + const size_t padding = 4096; + uint32_t size = (uint32_t)bx::getSize(&reader); + char* data = new char[size+padding+1]; + size = (uint32_t)bx::read(&reader, data, size); + + if (data[0] == '\xef' + && data[1] == '\xbb' + && data[2] == '\xbf') { - parse = bx::strws(parse); - const char* eol = bx::strFind(parse, ';'); - if (NULL == eol) - { - eol = bx::streol(parse); - } - - if (NULL != eol) - { - const char* precision = NULL; - const char* interpolation = NULL; - const char* typen = parse; - - if (0 == bx::strCmp(typen, "lowp", 4) - || 0 == bx::strCmp(typen, "mediump", 7) - || 0 == bx::strCmp(typen, "highp", 5) ) - { - precision = typen; - typen = parse = bx::strws(bx::strword(parse) ); - } - - if (0 == bx::strCmp(typen, "flat", 4) - || 0 == bx::strCmp(typen, "smooth", 6) - || 0 == bx::strCmp(typen, "noperspective", 13) - || 0 == bx::strCmp(typen, "centroid", 8) ) - { - interpolation = typen; - typen = parse = bx::strws(bx::strword(parse) ); - } - - const char* name = parse = bx::strws(bx::strword(parse) ); - const char* column = parse = bx::strws(bx::strword(parse) ); - const char* semantics = parse = bx::strws( (*parse == ':' ? ++parse : parse) ); - const char* assign = parse = bx::strws(bx::strword(parse) ); - const char* init = parse = bx::strws( (*parse == '=' ? ++parse : parse) ); - - if (typen < eol - && name < eol - && column < eol - && ':' == *column - && semantics < eol) - { - Varying var; - if (NULL != precision) - { - var.m_precision.assign(precision, bx::strword(precision)-precision); - } - - if (NULL != interpolation) - { - var.m_interpolation.assign(interpolation, bx::strword(interpolation)-interpolation); - } - - var.m_type.assign(typen, bx::strword(typen)-typen); - var.m_name.assign(name, bx::strword(name)-name); - var.m_semantics.assign(semantics, bx::strword(semantics)-semantics); - - if (d3d == 9 - && var.m_semantics == "BITANGENT") - { - var.m_semantics = "BINORMAL"; - } - - if (assign < eol - && '=' == *assign - && init < eol) - { - var.m_init.assign(init, eol-init); - } - - varyingMap.insert(std::make_pair(var.m_name, var) ); - } - - parse = bx::strws(bx::strnl(eol) ); - } + bx::memMove(data, &data[3], size-3); + size -= 3; } - InOut shaderInputs; - InOut shaderOutputs; - uint32_t inputHash = 0; - uint32_t outputHash = 0; + // Compiler generates "error X3000: syntax error: unexpected end of file" + // if input doesn't have empty line at EOF. + data[size] = '\n'; + bx::memSet(&data[size+1], 0, padding); + bx::close(&reader); - char* data; - char* input; + bx::FileWriter* writer = NULL; + + if (NULL != bin2c) { - const size_t padding = 4096; - uint32_t size = (uint32_t)bx::getSize(&reader); - data = new char[size+padding+1]; - size = (uint32_t)bx::read(&reader, data, size); - - if (data[0] == '\xef' - && data[1] == '\xbb' - && data[2] == '\xbf') - { - bx::memMove(data, &data[3], size-3); - size -= 3; - } - - // Compiler generates "error X3000: syntax error: unexpected end of file" - // if input doesn't have empty line at EOF. - data[size] = '\n'; - bx::memSet(&data[size+1], 0, padding); - bx::close(&reader); - - if (!raw) - { - // To avoid commented code being recognized as used feature, - // first preprocess pass is used to strip all comments before - // substituting code. - preprocessor.run(data); - delete [] data; - - size = (uint32_t)preprocessor.m_preprocessed.size(); - data = new char[size+padding+1]; - bx::memCopy(data, preprocessor.m_preprocessed.c_str(), size); - bx::memSet(&data[size], 0, padding+1); - } - - strNormalizeEol(data); - - input = const_cast(bx::strws(data) ); - while (input[0] == '$') - { - const char* str = bx::strws(input+1); - const char* eol = bx::streol(str); - const char* nl = bx::strnl(eol); - input = const_cast(nl); - - if (0 == bx::strCmp(str, "input", 5) ) - { - str += 5; - const char* comment = bx::strFind(str, "//"); - eol = NULL != comment && comment < eol ? comment : eol; - inputHash = parseInOut(shaderInputs, str, eol); - } - else if (0 == bx::strCmp(str, "output", 6) ) - { - str += 6; - const char* comment = bx::strFind(str, "//"); - eol = NULL != comment && comment < eol ? comment : eol; - outputHash = parseInOut(shaderOutputs, str, eol); - } - else if (0 == bx::strCmp(str, "raw", 3) ) - { - raw = true; - str += 3; - } - - input = const_cast(bx::strws(input) ); - } + writer = new Bin2cWriter(bin2c); + } + else + { + writer = new bx::FileWriter; } - if (raw) + if (!bx::open(writer, outFilePath) ) { - bx::FileWriter* writer = NULL; - - if (NULL != bin2c) - { - writer = new Bin2cWriter(bin2c); - } - else - { - writer = new bx::FileWriter; - } - - if (!bx::open(writer, outFilePath) ) - { - fprintf(stderr, "Unable to open output file '%s'.", outFilePath); - return bx::kExitFailure; - } - - if ('f' == shaderType) - { - bx::write(writer, BGFX_CHUNK_MAGIC_FSH); - bx::write(writer, inputHash); - } - else if ('v' == shaderType) - { - bx::write(writer, BGFX_CHUNK_MAGIC_VSH); - bx::write(writer, outputHash); - } - else - { - bx::write(writer, BGFX_CHUNK_MAGIC_CSH); - bx::write(writer, outputHash); - } - - if (0 != glsl) - { - bx::write(writer, uint16_t(0) ); - - uint32_t shaderSize = (uint32_t)bx::strLen(input); - bx::write(writer, shaderSize); - bx::write(writer, input, shaderSize); - bx::write(writer, uint8_t(0) ); - - compiled = true; - } - else if (0 != pssl) - { - compiled = compilePSSLShader(cmdLine, 0, input, writer); - } - else - { - compiled = compileHLSLShader(cmdLine, d3d, input, writer); - } - - bx::close(writer); - delete writer; - } - else if ('c' == shaderType) // Compute - { - char* entry = const_cast(bx::strFind(input, "void main()") ); - if (NULL == entry) - { - fprintf(stderr, "Shader entry point 'void main()' is not found.\n"); - } - else - { - if (0 != glsl - || 0 != essl - || 0 != metal) - { - } - else - { - preprocessor.writef( - "#define lowp\n" - "#define mediump\n" - "#define highp\n" - "#define ivec2 int2\n" - "#define ivec3 int3\n" - "#define ivec4 int4\n" - "#define uvec2 uint2\n" - "#define uvec3 uint3\n" - "#define uvec4 uint4\n" - "#define vec2 float2\n" - "#define vec3 float3\n" - "#define vec4 float4\n" - "#define mat2 float2x2\n" - "#define mat3 float3x3\n" - "#define mat4 float4x4\n" - ); - - entry[4] = '_'; - - preprocessor.writef("#define void_main()"); - preprocessor.writef(" \\\n\tvoid main("); - - uint32_t arg = 0; - - const bool hasLocalInvocationID = NULL != bx::strFind(input, "gl_LocalInvocationID"); - const bool hasLocalInvocationIndex = NULL != bx::strFind(input, "gl_LocalInvocationIndex"); - const bool hasGlobalInvocationID = NULL != bx::strFind(input, "gl_GlobalInvocationID"); - const bool hasWorkGroupID = NULL != bx::strFind(input, "gl_WorkGroupID"); - - if (hasLocalInvocationID) - { - preprocessor.writef( - " \\\n\t%sint3 gl_LocalInvocationID : SV_GroupThreadID" - , arg++ > 0 ? ", " : " " - ); - } - - if (hasLocalInvocationIndex) - { - preprocessor.writef( - " \\\n\t%sint gl_LocalInvocationIndex : SV_GroupIndex" - , arg++ > 0 ? ", " : " " - ); - } - - if (hasGlobalInvocationID) - { - preprocessor.writef( - " \\\n\t%sint3 gl_GlobalInvocationID : SV_DispatchThreadID" - , arg++ > 0 ? ", " : " " - ); - } - - if (hasWorkGroupID) - { - preprocessor.writef( - " \\\n\t%sint3 gl_WorkGroupID : SV_GroupID" - , arg++ > 0 ? ", " : " " - ); - } - - preprocessor.writef( - " \\\n\t)\n" - ); - } - - if (preprocessor.run(input) ) - { - BX_TRACE("Input file: %s", filePath); - BX_TRACE("Output file: %s", outFilePath); - - if (preprocessOnly) - { - bx::FileWriter writer; - - if (!bx::open(&writer, outFilePath) ) - { - fprintf(stderr, "Unable to open output file '%s'.", outFilePath); - return bx::kExitFailure; - } - - bx::write(&writer, preprocessor.m_preprocessed.c_str(), (int32_t)preprocessor.m_preprocessed.size() ); - bx::close(&writer); - - return bx::kExitSuccess; - } - - { - bx::FileWriter* writer = NULL; - - if (NULL != bin2c) - { - writer = new Bin2cWriter(bin2c); - } - else - { - writer = new bx::FileWriter; - } - - if (!bx::open(writer, outFilePath) ) - { - fprintf(stderr, "Unable to open output file '%s'.", outFilePath); - return bx::kExitFailure; - } - - bx::write(writer, BGFX_CHUNK_MAGIC_CSH); - bx::write(writer, outputHash); - - if (0 != glsl - || 0 != essl) - { - std::string code; - - if (essl) - { - bx::stringPrintf(code, "#version 310 es\n"); - } - else - { - bx::stringPrintf(code, "#version %d\n", glsl == 0 ? 430 : glsl); - } - - code += preprocessor.m_preprocessed; - #if 1 - bx::write(writer, uint16_t(0) ); - - uint32_t shaderSize = (uint32_t)code.size(); - bx::write(writer, shaderSize); - bx::write(writer, code.c_str(), shaderSize); - bx::write(writer, uint8_t(0) ); - - compiled = true; - #else - compiled = compileGLSLShader(cmdLine, essl, code, writer); - #endif // 0 - } - else if (0 != spirv) - { - compiled = compileSPIRVShader(cmdLine, 0, preprocessor.m_preprocessed, writer); - } - else if (0 != pssl) - { - compiled = compilePSSLShader(cmdLine, 0, preprocessor.m_preprocessed, writer); - } - else - { - compiled = compileHLSLShader(cmdLine, d3d, preprocessor.m_preprocessed, writer); - } - - bx::close(writer); - delete writer; - } - - if (compiled) - { - if (depends) - { - std::string ofp = outFilePath; - ofp += ".d"; - bx::FileWriter writer; - if (bx::open(&writer, ofp.c_str() ) ) - { - writef(&writer, "%s : %s\n", outFilePath, preprocessor.m_depends.c_str() ); - bx::close(&writer); - } - } - } - } - } - } - else // Vertex/Fragment - { - char* entry = const_cast(bx::strFind(input, "void main()") ); - if (NULL == entry) - { - fprintf(stderr, "Shader entry point 'void main()' is not found.\n"); - } - else - { - if (0 != glsl - || 0 != essl - || 0 != metal) - { - if (0 == essl) - { - // bgfx shadow2D/Proj behave like EXT_shadow_samplers - // not as GLSL language 1.2 specs shadow2D/Proj. - preprocessor.writef( - "#define shadow2D(_sampler, _coord) bgfxShadow2D(_sampler, _coord).x\n" - "#define shadow2DProj(_sampler, _coord) bgfxShadow2DProj(_sampler, _coord).x\n" - ); - } - - for (InOut::const_iterator it = shaderInputs.begin(), itEnd = shaderInputs.end(); it != itEnd; ++it) - { - VaryingMap::const_iterator varyingIt = varyingMap.find(*it); - if (varyingIt != varyingMap.end() ) - { - const Varying& var = varyingIt->second; - const char* name = var.m_name.c_str(); - - if (0 == bx::strCmp(name, "a_", 2) - || 0 == bx::strCmp(name, "i_", 2) ) - { - preprocessor.writef("attribute %s %s %s %s;\n" - , var.m_precision.c_str() - , var.m_interpolation.c_str() - , var.m_type.c_str() - , name - ); - } - else - { - preprocessor.writef("%s varying %s %s %s;\n" - , var.m_interpolation.c_str() - , var.m_precision.c_str() - , var.m_type.c_str() - , name - ); - } - } - } - - for (InOut::const_iterator it = shaderOutputs.begin(), itEnd = shaderOutputs.end(); it != itEnd; ++it) - { - VaryingMap::const_iterator varyingIt = varyingMap.find(*it); - if (varyingIt != varyingMap.end() ) - { - const Varying& var = varyingIt->second; - preprocessor.writef("%s varying %s %s;\n" - , var.m_interpolation.c_str() - , var.m_type.c_str() - , var.m_name.c_str() - ); - } - } - } - else - { - preprocessor.writef( - "#define lowp\n" - "#define mediump\n" - "#define highp\n" - "#define ivec2 int2\n" - "#define ivec3 int3\n" - "#define ivec4 int4\n" - "#define uvec2 uint2\n" - "#define uvec3 uint3\n" - "#define uvec4 uint4\n" - "#define vec2 float2\n" - "#define vec3 float3\n" - "#define vec4 float4\n" - "#define mat2 float2x2\n" - "#define mat3 float3x3\n" - "#define mat4 float4x4\n" - ); - - if (hlsl != 0 - && hlsl < 4) - { - preprocessor.writef( - "#define centroid\n" - "#define flat\n" - "#define noperspective\n" - "#define smooth\n" - ); - } - - entry[4] = '_'; - - if ('f' == shaderType) - { - const char* insert = bx::strFind(entry, "{"); - if (NULL != insert) - { - insert = strInsert(const_cast(insert+1), "\nvec4 bgfx_VoidFrag = vec4_splat(0.0);\n"); - } - - const bool hasFragColor = NULL != bx::strFind(input, "gl_FragColor"); - const bool hasFragCoord = NULL != bx::strFind(input, "gl_FragCoord") || hlsl > 3 || hlsl == 2; - const bool hasFragDepth = NULL != bx::strFind(input, "gl_FragDepth"); - const bool hasFrontFacing = NULL != bx::strFind(input, "gl_FrontFacing"); - const bool hasPrimitiveId = NULL != bx::strFind(input, "gl_PrimitiveID"); - - bool hasFragData[8] = {}; - uint32_t numFragData = 0; - for (uint32_t ii = 0; ii < BX_COUNTOF(hasFragData); ++ii) - { - char temp[32]; - bx::snprintf(temp, BX_COUNTOF(temp), "gl_FragData[%d]", ii); - hasFragData[ii] = NULL != bx::strFind(input, temp); - numFragData += hasFragData[ii]; - } - - if (0 == numFragData) - { - // GL errors when both gl_FragColor and gl_FragData is used. - // This will trigger the same error with HLSL compiler too. - preprocessor.writef("#define gl_FragColor gl_FragData_0_\n"); - - // If it has gl_FragData or gl_FragColor, color target at - // index 0 exists, otherwise shader is not modifying color - // targets. - hasFragData[0] |= hasFragColor || d3d < 11; - - if (NULL != insert - && d3d < 11 - && !hasFragColor) - { - insert = strInsert(const_cast(insert+1), "\ngl_FragColor = bgfx_VoidFrag;\n"); - } - } - - preprocessor.writef("#define void_main()"); - preprocessor.writef(" \\\n\tvoid main("); - - uint32_t arg = 0; - - if (hasFragCoord) - { - preprocessor.writef(" \\\n\tvec4 gl_FragCoord : SV_POSITION"); - ++arg; - } - - for (InOut::const_iterator it = shaderInputs.begin(), itEnd = shaderInputs.end(); it != itEnd; ++it) - { - VaryingMap::const_iterator varyingIt = varyingMap.find(*it); - if (varyingIt != varyingMap.end() ) - { - const Varying& var = varyingIt->second; - preprocessor.writef(" \\\n\t%s%s %s %s : %s" - , arg++ > 0 ? ", " : " " - , interpolationDx11(var.m_interpolation.c_str() ) - , var.m_type.c_str() - , var.m_name.c_str() - , var.m_semantics.c_str() - ); - } - } - - const uint32_t maxRT = d3d > 9 ? BX_COUNTOF(hasFragData) : 4; - - for (uint32_t ii = 0; ii < BX_COUNTOF(hasFragData); ++ii) - { - if (ii < maxRT) - { - if (hasFragData[ii]) - { - addFragData(preprocessor, input, ii, arg++ > 0); - } - } - else - { - voidFragData(input, ii); - } - } - - if (hasFragDepth) - { - preprocessor.writef( - " \\\n\t%sout float gl_FragDepth : SV_DEPTH" - , arg++ > 0 ? ", " : " " - ); - } - - if (hasFrontFacing - && hlsl >= 3) - { - preprocessor.writef( - " \\\n\t%sfloat __vface : VFACE" - , arg++ > 0 ? ", " : " " - ); - } - - if (hasPrimitiveId) - { - if (d3d > 9) - { - preprocessor.writef( - " \\\n\t%suint gl_PrimitiveID : SV_PrimitiveID" - , arg++ > 0 ? ", " : " " - ); - } - else - { - fprintf(stderr, "gl_PrimitiveID builtin is not supported by this D3D9 HLSL.\n"); - return bx::kExitFailure; - } - } - - preprocessor.writef( - " \\\n\t)\n" - ); - - if (hasFrontFacing) - { - if (hlsl >= 3) - { - preprocessor.writef( - "#define gl_FrontFacing (__vface <= 0.0)\n" - ); - } - else - { - preprocessor.writef( - "#define gl_FrontFacing false\n" - ); - } - } - } - else if ('v' == shaderType) - { - const bool hasVertexId = NULL != bx::strFind(input, "gl_VertexID"); - const bool hasInstanceId = NULL != bx::strFind(input, "gl_InstanceID"); - - const char* brace = bx::strFind(entry, "{"); - if (NULL != brace) - { - const char* end = bx::strmb(brace, '{', '}'); - if (NULL != end) - { - strInsert(const_cast(end), "__RETURN__;\n"); - } - } - - preprocessor.writef( - "struct Output\n" - "{\n" - "\tvec4 gl_Position : SV_POSITION;\n" - "#define gl_Position _varying_.gl_Position\n" - ); - for (InOut::const_iterator it = shaderOutputs.begin(), itEnd = shaderOutputs.end(); it != itEnd; ++it) - { - VaryingMap::const_iterator varyingIt = varyingMap.find(*it); - if (varyingIt != varyingMap.end() ) - { - const Varying& var = varyingIt->second; - preprocessor.writef("\t%s %s : %s;\n", var.m_type.c_str(), var.m_name.c_str(), var.m_semantics.c_str() ); - preprocessor.writef("#define %s _varying_.%s\n", var.m_name.c_str(), var.m_name.c_str() ); - } - } - preprocessor.writef( - "};\n" - ); - - preprocessor.writef("#define void_main() \\\n"); - preprocessor.writef("Output main("); - uint32_t arg = 0; - for (InOut::const_iterator it = shaderInputs.begin(), itEnd = shaderInputs.end(); it != itEnd; ++it) - { - VaryingMap::const_iterator varyingIt = varyingMap.find(*it); - if (varyingIt != varyingMap.end() ) - { - const Varying& var = varyingIt->second; - preprocessor.writef( - " \\\n\t%s%s %s : %s" - , arg++ > 0 ? ", " : "" - , var.m_type.c_str() - , var.m_name.c_str() - , var.m_semantics.c_str() - ); - } - } - - if (hasVertexId) - { - if (d3d > 9) - { - preprocessor.writef( - " \\\n\t%suint gl_VertexID : SV_VertexID" - , arg++ > 0 ? ", " : " " - ); - } - else - { - fprintf(stderr, "gl_VertexID builtin is not supported by this D3D9 HLSL.\n"); - return bx::kExitFailure; - } - } - - if (hasInstanceId) - { - if (d3d > 9) - { - preprocessor.writef( - " \\\n\t%suint gl_InstanceID : SV_InstanceID" - , arg++ > 0 ? ", " : " " - ); - } - else - { - fprintf(stderr, "gl_InstanceID builtin is not supported by this D3D9 HLSL.\n"); - return bx::kExitFailure; - } - } - - preprocessor.writef( - ") \\\n" - "{ \\\n" - "\tOutput _varying_;" - ); - - for (InOut::const_iterator it = shaderOutputs.begin(), itEnd = shaderOutputs.end(); it != itEnd; ++it) - { - VaryingMap::const_iterator varyingIt = varyingMap.find(*it); - if (varyingIt != varyingMap.end() ) - { - const Varying& var = varyingIt->second; - preprocessor.writef(" \\\n\t%s", var.m_name.c_str() ); - if (!var.m_init.empty() ) - { - preprocessor.writef(" = %s", var.m_init.c_str() ); - } - preprocessor.writef(";"); - } - } - - preprocessor.writef( - "\n#define __RETURN__ \\\n" - "\t} \\\n" - ); - - if (hlsl != 0 - && hlsl <= 3) - { -// preprocessor.writef( -// "\tgl_Position.xy += u_viewTexel.xy * gl_Position.w; \\\n" -// ); - } - - preprocessor.writef( - "\treturn _varying_" - ); - } - } - - if (preprocessor.run(input) ) - { - BX_TRACE("Input file: %s", filePath); - BX_TRACE("Output file: %s", outFilePath); - - if (preprocessOnly) - { - bx::FileWriter writer; - - if (!bx::open(&writer, outFilePath) ) - { - fprintf(stderr, "Unable to open output file '%s'.", outFilePath); - return bx::kExitFailure; - } - - if (0 != glsl) - { - if (NULL == profile) - { - writef(&writer - , "#ifdef GL_ES\n" - "precision highp float;\n" - "#endif // GL_ES\n\n" - ); - } - } - bx::write(&writer, preprocessor.m_preprocessed.c_str(), (int32_t)preprocessor.m_preprocessed.size() ); - bx::close(&writer); - - return bx::kExitSuccess; - } - - { - bx::FileWriter* writer = NULL; - - if (NULL != bin2c) - { - writer = new Bin2cWriter(bin2c); - } - else - { - writer = new bx::FileWriter; - } - - if (!bx::open(writer, outFilePath) ) - { - fprintf(stderr, "Unable to open output file '%s'.", outFilePath); - return bx::kExitFailure; - } - - if ('f' == shaderType) - { - bx::write(writer, BGFX_CHUNK_MAGIC_FSH); - bx::write(writer, inputHash); - } - else if ('v' == shaderType) - { - bx::write(writer, BGFX_CHUNK_MAGIC_VSH); - bx::write(writer, outputHash); - } - else - { - bx::write(writer, BGFX_CHUNK_MAGIC_CSH); - bx::write(writer, outputHash); - } - - if (0 != glsl - || 0 != essl - || 0 != metal) - { - std::string code; - - if (glsl < 400) - { - const bool usesTextureLod = false - || !!bx::findIdentifierMatch(input, s_ARB_shader_texture_lod) - || !!bx::findIdentifierMatch(input, s_EXT_shader_texture_lod) - ; - const bool usesInstanceID = !!bx::strFind(input, "gl_InstanceID"); - const bool usesGpuShader4 = !!bx::findIdentifierMatch(input, s_EXT_gpu_shader4); - const bool usesGpuShader5 = !!bx::findIdentifierMatch(input, s_ARB_gpu_shader5); - const bool usesTexelFetch = !!bx::findIdentifierMatch(input, s_texelFetch); - const bool usesTextureMS = !!bx::findIdentifierMatch(input, s_ARB_texture_multisample); - const bool usesTextureArray = !!bx::findIdentifierMatch(input, s_textureArray); - const bool usesPacking = !!bx::findIdentifierMatch(input, s_ARB_shading_language_packing); - - if (0 == essl) - { - const bool need130 = 120 == glsl && (false - || bx::findIdentifierMatch(input, s_130) - || usesTexelFetch - ); - - if (0 != metal) - { - bx::stringPrintf(code, "#version 120\n"); - } - else - { - bx::stringPrintf(code, "#version %s\n", need130 ? "130" : profile); - glsl = 130; - } - - if (usesInstanceID) - { - bx::stringPrintf(code - , "#extension GL_ARB_draw_instanced : enable\n" - ); - } - - if (usesGpuShader4) - { - bx::stringPrintf(code - , "#extension GL_EXT_gpu_shader4 : enable\n" - ); - } - - if (usesGpuShader5) - { - bx::stringPrintf(code - , "#extension GL_ARB_gpu_shader5 : enable\n" - ); - } - - if (usesPacking) - { - bx::stringPrintf(code - , "#extension GL_ARB_shading_language_packing : enable\n" - ); - } - - bool ARB_shader_texture_lod = false; - bool EXT_shader_texture_lod = false; - - if (usesTextureLod) - { - if ('f' == shaderType) - { - ARB_shader_texture_lod = true; - bx::stringPrintf(code - , "#extension GL_ARB_shader_texture_lod : enable\n" - ); - } - else - { - EXT_shader_texture_lod = true; - bx::stringPrintf(code - , "#extension GL_EXT_shader_texture_lod : enable\n" - ); - } - } - - if (usesTextureMS) - { - bx::stringPrintf(code - , "#extension GL_ARB_texture_multisample : enable\n" - ); - } - - if (usesTextureArray) - { - bx::stringPrintf(code - , "#extension GL_EXT_texture_array : enable\n" - ); - } - - if (130 > glsl) - { - bx::stringPrintf(code, - "#define ivec2 vec2\n" - "#define ivec3 vec3\n" - "#define ivec4 vec4\n" - ); - } - - if (ARB_shader_texture_lod) - { - bx::stringPrintf(code, - "#define texture2DProjLod texture2DProjLodARB\n" - "#define texture2DGrad texture2DGradARB\n" - "#define texture2DProjGrad texture2DProjGradARB\n" - "#define textureCubeGrad textureCubeGradARB\n" - ); - } - else if (EXT_shader_texture_lod) - { - bx::stringPrintf(code, - "#define texture2DProjLod texture2DProjLodEXT\n" - "#define texture2DGrad texture2DGradEXT\n" - "#define texture2DProjGrad texture2DProjGradEXT\n" - "#define textureCubeGrad textureCubeGradEXT\n" - ); - } - - if (need130) - { - bx::stringPrintf(code - , "#define bgfxShadow2D(_sampler, _coord) vec4_splat(texture(_sampler, _coord))\n" - "#define bgfxShadow2DProj(_sampler, _coord) vec4_splat(textureProj(_sampler, _coord))\n" - ); - } - else - { - bx::stringPrintf(code - , "#define bgfxShadow2D shadow2D\n" - "#define bgfxShadow2DProj shadow2DProj\n" - ); - } - } - else - { - // Pretend that all extensions are available. - // This will be stripped later. - if (usesTextureLod) - { - bx::stringPrintf(code - , "#extension GL_EXT_shader_texture_lod : enable\n" - "#define texture2DLod texture2DLodEXT\n" - "#define texture2DGrad texture2DGradEXT\n" - "#define texture2DProjLod texture2DProjLodEXT\n" - "#define texture2DProjGrad texture2DProjGradEXT\n" - "#define textureCubeLod textureCubeLodEXT\n" - "#define textureCubeGrad textureCubeGradEXT\n" - ); - } - - if (NULL != bx::findIdentifierMatch(input, s_OES_standard_derivatives) ) - { - bx::stringPrintf(code, "#extension GL_OES_standard_derivatives : enable\n"); - } - - if (NULL != bx::findIdentifierMatch(input, s_OES_texture_3D) ) - { - bx::stringPrintf(code, "#extension GL_OES_texture_3D : enable\n"); - } - - if (NULL != bx::findIdentifierMatch(input, s_EXT_shadow_samplers) ) - { - bx::stringPrintf(code - , "#extension GL_EXT_shadow_samplers : enable\n" - "#define shadow2D shadow2DEXT\n" - "#define shadow2DProj shadow2DProjEXT\n" - ); - } - - if (usesGpuShader5) - { - bx::stringPrintf(code - , "#extension GL_ARB_gpu_shader5 : enable\n" - ); - } - - if (usesPacking) - { - bx::stringPrintf(code - , "#extension GL_ARB_shading_language_packing : enable\n" - ); - } - - if (NULL != bx::findIdentifierMatch(input, "gl_FragDepth") ) - { - bx::stringPrintf(code - , "#extension GL_EXT_frag_depth : enable\n" - "#define gl_FragDepth gl_FragDepthEXT\n" - ); - } - - if (usesTextureArray) - { - bx::stringPrintf(code - , "#extension GL_EXT_texture_array : enable\n" - ); - } - - bx::stringPrintf(code, - "#define ivec2 vec2\n" - "#define ivec3 vec3\n" - "#define ivec4 vec4\n" - ); - } - } - else - { - bx::stringPrintf(code, "#version %d\n", glsl); - } - - code += preprocessor.m_preprocessed; - - if (glsl > 400) - { - bx::write(writer, uint16_t(0) ); - - uint32_t shaderSize = (uint32_t)code.size(); - bx::write(writer, shaderSize); - bx::write(writer, code.c_str(), shaderSize); - bx::write(writer, uint8_t(0) ); - - compiled = true; - } - else - { - compiled = compileGLSLShader(cmdLine - , metal ? BX_MAKEFOURCC('M', 'T', 'L', 0) : essl - , code - , writer - ); - } - } - else if (0 != spirv) - { - compiled = compileSPIRVShader(cmdLine - , 0 - , preprocessor.m_preprocessed - , writer - ); - } - else if (0 != pssl) - { - compiled = compilePSSLShader(cmdLine - , 0 - , preprocessor.m_preprocessed - , writer - ); - } - else - { - compiled = compileHLSLShader(cmdLine - , d3d - , preprocessor.m_preprocessed - , writer - ); - } - - bx::close(writer); - delete writer; - } - - if (compiled) - { - if (depends) - { - std::string ofp = outFilePath; - ofp += ".d"; - bx::FileWriter writer; - if (bx::open(&writer, ofp.c_str() ) ) - { - writef(&writer, "%s : %s\n", outFilePath, preprocessor.m_depends.c_str() ); - bx::close(&writer); - } - } - } - } - } + fprintf(stderr, "Unable to open output file '%s'.", outFilePath); + return bx::kExitFailure; } - delete [] data; + if ( compileShader(attribdef.getData(), data, size, options, writer) ) + compiled = true; + + bx::close(writer); + delete writer; } if (compiled) diff --git a/tools/shaderc/shaderc.h b/tools/shaderc/shaderc.h index f829cae06..ef69add4b 100644 --- a/tools/shaderc/shaderc.h +++ b/tools/shaderc/shaderc.h @@ -122,6 +122,41 @@ namespace bgfx uint16_t regCount; }; + struct Options + { + Options(); + + void dump(); + + char shaderType; + std::string platform; + std::string profile; + + std::string inputFilePath; + std::string outputFilePath; + + std::vector includeDirs; + std::vector defines; + std::vector dependencies; + + bool disasm; + bool raw; + bool preprocessOnly; + bool depends; + + bool debugInformation; + + bool avoidFlowControl; + bool noPreshader; + bool partialPrecision; + bool preferFlowControl; + bool backwardsCompatibility; + bool warningsAreErrors; + + bool optimize; + uint32_t optimizationLevel; + }; + typedef std::vector UniformArray; void printCode(const char* _code, int32_t _line = 0, int32_t _start = 0, int32_t _end = INT32_MAX, int32_t _column = -1); @@ -129,10 +164,10 @@ namespace bgfx int32_t writef(bx::WriterI* _writer, const char* _format, ...); void writeFile(const char* _filePath, const void* _data, int32_t _size); - bool compileGLSLShader(const bx::CommandLine& _cmdLine, uint32_t _version, const std::string& _code, bx::WriterI* _writer); - bool compileHLSLShader(const bx::CommandLine& _cmdLine, uint32_t _version, const std::string& _code, bx::WriterI* _writer); - bool compilePSSLShader(const bx::CommandLine& _cmdLine, uint32_t _version, const std::string& _code, bx::WriterI* _writer); - bool compileSPIRVShader(const bx::CommandLine& _cmdLine, uint32_t _version, const std::string& _code, bx::WriterI* _writer); + bool compileGLSLShader(const Options& _options, uint32_t _version, const std::string& _code, bx::WriterI* _writer); + bool compileHLSLShader(const Options& _options, uint32_t _version, const std::string& _code, bx::WriterI* _writer); + bool compilePSSLShader(const Options& _options, uint32_t _version, const std::string& _code, bx::WriterI* _writer); + bool compileSPIRVShader(const Options& _options, uint32_t _version, const std::string& _code, bx::WriterI* _writer); } // namespace bgfx diff --git a/tools/shaderc/shaderc_glsl.cpp b/tools/shaderc/shaderc_glsl.cpp index f9aeb995b..7d2a0a1cd 100644 --- a/tools/shaderc/shaderc_glsl.cpp +++ b/tools/shaderc/shaderc_glsl.cpp @@ -8,9 +8,9 @@ namespace bgfx { namespace glsl { - static bool compile(const bx::CommandLine& _cmdLine, uint32_t _version, const std::string& _code, bx::WriterI* _writer) + static bool compile(const Options& _options, uint32_t _version, const std::string& _code, bx::WriterI* _writer) { - char ch = char(tolower(_cmdLine.findOption('\0', "type")[0]) ); + char ch = _options.shaderType; const glslopt_shader_type type = ch == 'f' ? kGlslOptShaderFragment : (ch == 'c' ? kGlslOptShaderCompute : kGlslOptShaderVertex); @@ -292,10 +292,9 @@ namespace bgfx { namespace glsl uint8_t nul = 0; bx::write(_writer, nul); - if (_cmdLine.hasArg('\0', "disasm") ) + if (_options.disasm ) { - std::string disasmfp = _cmdLine.findOption('o'); - disasmfp += ".disasm"; + std::string disasmfp = _options.outputFilePath + ".disasm"; writeFile(disasmfp.c_str(), optimizedShader, shaderSize); } @@ -306,9 +305,9 @@ namespace bgfx { namespace glsl } // namespace glsl - bool compileGLSLShader(const bx::CommandLine& _cmdLine, uint32_t _version, const std::string& _code, bx::WriterI* _writer) + bool compileGLSLShader(const Options& _options, uint32_t _version, const std::string& _code, bx::WriterI* _writer) { - return glsl::compile(_cmdLine, _version, _code, _writer); + return glsl::compile(_options, _version, _code, _writer); } } // namespace bgfx diff --git a/tools/shaderc/shaderc_hlsl.cpp b/tools/shaderc/shaderc_hlsl.cpp index 123ed32f6..f68c20c59 100644 --- a/tools/shaderc/shaderc_hlsl.cpp +++ b/tools/shaderc/shaderc_hlsl.cpp @@ -545,10 +545,11 @@ namespace bgfx { namespace hlsl return true; } - static bool compile(const bx::CommandLine& _cmdLine, uint32_t _version, const std::string& _code, bx::WriterI* _writer, bool _firstPass) + static bool compile(const Options& _options, uint32_t _version, const std::string& _code, bx::WriterI* _writer, bool _firstPass) { - const char* profile = _cmdLine.findOption('p', "profile"); - if (NULL == profile) + const char* profile = _options.profile.c_str(); + + if (profile[0] == '\0') { fprintf(stderr, "Error: Shader profile must be specified.\n"); return false; @@ -557,27 +558,26 @@ namespace bgfx { namespace hlsl s_compiler = load(); bool result = false; - bool debug = _cmdLine.hasArg('\0', "debug"); + bool debug = _options.debugInformation; uint32_t flags = D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY; flags |= debug ? D3DCOMPILE_DEBUG : 0; - flags |= _cmdLine.hasArg('\0', "avoid-flow-control") ? D3DCOMPILE_AVOID_FLOW_CONTROL : 0; - flags |= _cmdLine.hasArg('\0', "no-preshader") ? D3DCOMPILE_NO_PRESHADER : 0; - flags |= _cmdLine.hasArg('\0', "partial-precision") ? D3DCOMPILE_PARTIAL_PRECISION : 0; - flags |= _cmdLine.hasArg('\0', "prefer-flow-control") ? D3DCOMPILE_PREFER_FLOW_CONTROL : 0; - flags |= _cmdLine.hasArg('\0', "backwards-compatibility") ? D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY : 0; + flags |= _options.avoidFlowControl ? D3DCOMPILE_AVOID_FLOW_CONTROL : 0; + flags |= _options.noPreshader ? D3DCOMPILE_NO_PRESHADER : 0; + flags |= _options.partialPrecision ? D3DCOMPILE_PARTIAL_PRECISION : 0; + flags |= _options.preferFlowControl ? D3DCOMPILE_PREFER_FLOW_CONTROL : 0; + flags |= _options.backwardsCompatibility ? D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY : 0; - bool werror = _cmdLine.hasArg('\0', "Werror"); + bool werror = _options.warningsAreErrors; if (werror) { flags |= D3DCOMPILE_WARNINGS_ARE_ERRORS; } - uint32_t optimization = 3; - if (_cmdLine.hasArg(optimization, 'O') ) + if (_options.optimize ) { - optimization = bx::uint32_min(optimization, BX_COUNTOF(s_optimizationLevelD3D11) - 1); + uint32_t optimization = bx::uint32_min(_options.optimizationLevel, BX_COUNTOF(s_optimizationLevelD3D11) - 1); flags |= s_optimizationLevelD3D11[optimization]; } else @@ -598,8 +598,7 @@ namespace bgfx { namespace hlsl if (debug) { - hlslfp = _cmdLine.findOption('o'); - hlslfp += ".hlsl"; + hlslfp = _options.outputFilePath + ".hlsl"; writeFile(hlslfp.c_str(), _code.c_str(), (int32_t)_code.size() ); } @@ -708,7 +707,7 @@ namespace bgfx { namespace hlsl } // recompile with the unused uniforms converted to statics - return compile(_cmdLine, _version, output.c_str(), _writer, false); + return compile(_options, _version, output.c_str(), _writer, false); } } @@ -771,7 +770,7 @@ namespace bgfx { namespace hlsl bx::write(_writer, size); } - if (_cmdLine.hasArg('\0', "disasm") ) + if (_options.disasm ) { ID3DBlob* disasm; D3DDisassemble(code->GetBufferPointer() @@ -783,8 +782,7 @@ namespace bgfx { namespace hlsl if (NULL != disasm) { - std::string disasmfp = _cmdLine.findOption('o'); - disasmfp += ".disasm"; + std::string disasmfp = _options.outputFilePath + ".disasm"; writeFile(disasmfp.c_str(), disasm->GetBufferPointer(), (uint32_t)disasm->GetBufferSize() ); disasm->Release(); @@ -806,9 +804,9 @@ namespace bgfx { namespace hlsl } // namespace hlsl - bool compileHLSLShader(const bx::CommandLine& _cmdLine, uint32_t _version, const std::string& _code, bx::WriterI* _writer) + bool compileHLSLShader(const Options& _options, uint32_t _version, const std::string& _code, bx::WriterI* _writer) { - return hlsl::compile(_cmdLine, _version, _code, _writer, true); + return hlsl::compile(_options, _version, _code, _writer, true); } } // namespace bgfx @@ -817,9 +815,9 @@ namespace bgfx { namespace hlsl namespace bgfx { - bool compileHLSLShader(const bx::CommandLine& _cmdLine, uint32_t _version, const std::string& _code, bx::WriterI* _writer) + bool compileHLSLShader(const Options& _options, uint32_t _version, const std::string& _code, bx::WriterI* _writer) { - BX_UNUSED(_cmdLine, _version, _code, _writer); + BX_UNUSED(_options, _version, _code, _writer); fprintf(stderr, "HLSL compiler is not supported on this platform.\n"); return false; } diff --git a/tools/shaderc/shaderc_pssl.cpp b/tools/shaderc/shaderc_pssl.cpp index cb176d22e..87fe55846 100644 --- a/tools/shaderc/shaderc_pssl.cpp +++ b/tools/shaderc/shaderc_pssl.cpp @@ -7,9 +7,9 @@ namespace bgfx { - bool compilePSSLShader(const bx::CommandLine& _cmdLine, uint32_t _version, const std::string& _code, bx::WriterI* _writer) + bool compilePSSLShader(const Options& _options, uint32_t _version, const std::string& _code, bx::WriterI* _writer) { - BX_UNUSED(_cmdLine, _version, _code, _writer); + BX_UNUSED(_options, _version, _code, _writer); fprintf(stderr, "PSSL compiler is not supported.\n"); return false; } diff --git a/tools/shaderc/shaderc_spirv.cpp b/tools/shaderc/shaderc_spirv.cpp index b4fef5b9f..314d6838f 100644 --- a/tools/shaderc/shaderc_spirv.cpp +++ b/tools/shaderc/shaderc_spirv.cpp @@ -545,25 +545,18 @@ namespace bgfx { namespace spirv // fprintf(stderr, "%s\n", _message); // } - static bool compile(const bx::CommandLine& _cmdLine, uint32_t _version, const std::string& _code, bx::WriterI* _writer) + static bool compile(const Options& _options, uint32_t _version, const std::string& _code, bx::WriterI* _writer) { - BX_UNUSED(_cmdLine, _version, _code, _writer); - - const char* type = _cmdLine.findOption('\0', "type"); - if (NULL == type) - { - fprintf(stderr, "Error: Shader type must be specified.\n"); - return false; - } + BX_UNUSED(_version); glslang::InitializeProcess(); glslang::TProgram* program = new glslang::TProgram; - EShLanguage stage = getLang(type[0]); + EShLanguage stage = getLang(_options.shaderType); if (EShLangCount == stage) { - fprintf(stderr, "Error: Unknown shader type %s.\n", type); + fprintf(stderr, "Error: Unknown shader type %s.\n", _options.shaderType); return false; } glslang::TShader* shader = new glslang::TShader(stage); @@ -649,7 +642,7 @@ namespace bgfx { namespace spirv uint16_t count = (uint16_t)program->getNumLiveUniformVariables(); bx::write(_writer, count); - uint32_t fragmentBit = type[0] == 'f' ? BGFX_UNIFORM_FRAGMENTBIT : 0; + uint32_t fragmentBit = _options.shaderType == 'f' ? BGFX_UNIFORM_FRAGMENTBIT : 0; for (uint16_t ii = 0; ii < count; ++ii) { Uniform un; @@ -767,9 +760,9 @@ namespace bgfx { namespace spirv } // namespace spirv - bool compileSPIRVShader(const bx::CommandLine& _cmdLine, uint32_t _version, const std::string& _code, bx::WriterI* _writer) + bool compileSPIRVShader(const Options& _options, uint32_t _version, const std::string& _code, bx::WriterI* _writer) { - return spirv::compile(_cmdLine, _version, _code, _writer); + return spirv::compile(_options, _version, _code, _writer); } } // namespace bgfx