コード例 #1
0
	// ------------------------------------------------------------------------------------------
	//! Generates the HLSL shader Byte code.
	//! @param ShaderByteCodeOutputStream Output for the shader code.
	//! @param ShaderParsedData Parsed shader data, produced by @ref HLSLParser
	//! @param ShaderType Type of the shader to generate code.
	//! @param ShaderEntryName Name of the shader entry point.
	//! @param ShaderTargetPlatform Target platform for the GLSL code.
	void GLSLCompiler::GenerateAndCompileShader(UniquePtr<OutputStream> const& ShaderByteCodeOutputStream
		, HLSLScope const* const ShaderParsedData, IGraphicsShaderType const ShaderType, String const& ShaderEntryName
		, DHLSLShaderCrossCompilerTarget const ShaderTargetPlatform)
	{
		StringBuilder GLSLGeneratorBuilder;
		GLSLGenerator().GenerateShader(GLSLGeneratorBuilder, ShaderParsedData, ShaderEntryName, ShaderTargetPlatform, ShaderType);

		// Now we need just preprocess generated code to reduce loading time.
		StringBuilder GLSLPreprocessedBuilder;
		GLSLPreprocessedBuilder.Append(GLSLInsertations::GLSLCopyright);
		GLSLPreprocessedBuilder.Append(GLSLInsertations::GLSLPreambule[ShaderTargetPlatform - DHLSL_CC_TARGET_GLSL430]);

		// We use MCPP preprocessor because it is faster than our one.
		//! @todo Implement temporary files access here.
		String const MCPPSourceFilePath = "a.tmp";// Path::GetTemporaryFileName();
		String const MCPPOutputFilePath = "b.tmp";// Path::GetTemporaryFileName();
		CStr   const MCPPArguments[] = { nullptr, "-P", MCPPSourceFilePath.CStr(), MCPPOutputFilePath.CStr() };

		// Saving output to some temporary file to make is accessible from MCPP
		FileOutputStream MCPPSourceFile(/*MCPPSourceFilePath*/L"a.tmp");
		MCPPSourceFile.Write(GLSLGeneratorBuilder.CStr(), GLSLGeneratorBuilder.GetLength(), sizeof(Char));
		MCPPSourceFile.Close();

		{ 
		//	MCPP is not thread-safe.
		//	CriticalSection static MCPPCriticalSection;
		//	ScopedCriticalSection MCPPLock(MCPPCriticalSection);
			int const MCPPResult = mcpp_lib_main(GD_ARRAY_LENGTH(MCPPArguments), const_cast<char**>(&MCPPArguments[0]));
			GD_DEBUG_ASSERT(MCPPResult == 0, "Failed to preprocess shader source.");
		}
		// Reading MCPP result.
		{
			FileInputStream MCPPOutputFile(/*MCPPOutputFilePath*/L"b.tmp");
			SizeTp const GLSLPreprocessedBuilderPos = GLSLPreprocessedBuilder.GetLength();
			GLSLPreprocessedBuilder.Resize(GLSLPreprocessedBuilder.GetLength() + (UInt32) MCPPOutputFile.GetLength());
			MCPPOutputFile.Read(GLSLPreprocessedBuilder.CStr() + GLSLPreprocessedBuilderPos, MCPPOutputFile.GetLength(), 1);
			MCPPOutputFile.Close();
			GLSLPreprocessedBuilder.Append('\0');
			GD_DEBUG_ASSERT(::remove(MCPPSourceFilePath.CStr()) == 0, "Failed to remove mcpp source file.");
			GD_DEBUG_ASSERT(::remove(MCPPOutputFilePath.CStr()) == 0, "Failed to remove mcpp output file.");
		}

		// Trying to optimize the GLSL code..
		StringBuilder GLSLOptimizerBuilder;
		/**/if (ShaderTargetPlatform != DHLSL_CC_TARGET_GLSL430									// glsl_optimizer supports only desktop GLSL 140 version. We are using 430...			
			&& (ShaderType != IGRAPHICS_SHADER_TYPE_VERTEX && ShaderType != IGRAPHICS_SHADER_TYPE_PIXEL))	// glsl_optimizer supports only vertex and pixel shaders...
		{
			// Optimizing is supported for this shader type and target.
			glslopt_target static const IGraphicsGLSLangTargetsTable[] = {
				/* DHLSL_CC_TARGET_GLSL430 */ kGlslTargetOpenGL,
				/* DHLSL_CC_TARGET_GLSLES3 */ kGlslTargetOpenGLES20,
				/* DHLSL_CC_TARGET_GLSLES2 */ kGlslTargetOpenGLES30,
			};
			glslopt_shader_type static const IGraphicsGLSLangShaderTypesTable[] = {
				/* IGRAPHICS_SHADER_TYPE_VERTEX */ kGlslOptShaderVertex,
				/* IGRAPHICS_SHADER_TYPE_PIXEL  */ kGlslOptShaderFragment,
			};

			auto const OptimizerContext = glslopt_initialize(IGraphicsGLSLangTargetsTable[ShaderTargetPlatform]);
			auto const OptimizedShader = glslopt_optimize(OptimizerContext, IGraphicsGLSLangShaderTypesTable[ShaderType - DHLSL_CC_TARGET_GLSL430]
				, GLSLPreprocessedBuilder.CStr(), kGlslOptionSkipPreprocessor);
			if (!glslopt_get_status(OptimizedShader))
			{
				// Shader was not optimized..
				// This does not mean that our shader is incorrect, just MESA-based optimizer may not parse
#if 0			// our code correctly.
				CStr const ShaderOptimizationLog = glslopt_get_log(OptimizedShader);
				throw GLSLCompilerErrorException("shader optimization failed with following log: \n%s", ShaderOptimizationLog);
#endif	// if 0
				GLSLOptimizerBuilder = Move(GLSLPreprocessedBuilder);
			}
			else
			{
				// Shader was optimized..
				GLSLOptimizerBuilder.Append(glslopt_get_output(OptimizedShader));
			}

			glslopt_shader_delete(OptimizedShader);
			glslopt_cleanup(OptimizerContext);
		}
		else
		{
			// Shader was not optimized - using default version.
			GLSLOptimizerBuilder = Move(GLSLPreprocessedBuilder);
		}

		// No we need to validate our shader.. 
		TBuiltInResource static const GLSLangDefaultResources{ INT_MAX };
		EShLanguage static const IGraphicsGLSLangShaderTypesTable[IGRAPHICS_SHADER_TYPES_COUNT] = {
			/* IGRAPHICS_SHADER_TYPE_VERTEX   */ EShLangVertex,
			/* IGRAPHICS_SHADER_TYPE_PIXEL    */ EShLangFragment,
			/* IGRAPHICS_SHADER_TYPE_GEOMETRY */ EShLangGeometry,
			/* IGRAPHICS_SHADER_TYPE_HULL     */ EShLangTessControl,
			/* IGRAPHICS_SHADER_TYPE_DOMAIN   */ EShLangTessEvaluation,
			/* IGRAPHICS_SHADER_TYPE_COMPUTE  */ EShLangCompute,
			/* IGRAPHICS_SHADER_TYPE_UNKNOWN  */ EShLangCount,
		};

		glslang::InitializeProcess();

		// Trying to compile our shader..
		char const* const GLSLOptimizerBuilderPtr = GLSLOptimizerBuilder.CStr();
		glslang::TShader GLSLangShader(IGraphicsGLSLangShaderTypesTable[ShaderType]);
		GLSLangShader.setStrings(&GLSLOptimizerBuilderPtr, 1);
		if (!GLSLangShader.parse(&GLSLangDefaultResources, 100, true, EShMsgDefault))
		{ 
			// Failed to compile our shader.
			throw GLSLCompilerErrorException("GLSLang compilation returned errors: \n%s\nGenerated code:\n%s", GLSLangShader.getInfoLog(), GLSLOptimizerBuilderPtr);
		}
		else
		{
#if 0
			Debug::Log(GLSLangShader.getInfoLog());
#endif	// if 0
		}

		// Trying to link our shader program..
		glslang::TProgram GLSLangProgram;
		GLSLangProgram.addShader(&GLSLangShader);
		if (!GLSLangProgram.link(EShMsgDefault))
		{ 
			throw GLSLCompilerErrorException("GLSLang linking returned errors: \n%s", GLSLangProgram.getInfoLog());
		}
		else
		{
#if 0
			Debug::Log(GLSLangProgram.getInfoLog());
#endif	// if 0
		}

		glslang::FinalizeProcess();

		ShaderByteCodeOutputStream->Write(GLSLOptimizerBuilder.CStr(), GLSLOptimizerBuilder.GetLength(), sizeof(Char));
	}
コード例 #2
0
	// ------------------------------------------------------------------------------------------
	//! @todo Document and cleanup me.
	void GLSLGenerator::GenerateShaderEntryPoint(HLSLFunction const* const EntryPoint, StringBuilder& Builder)
	{
		StringBuilder FakeEntryAssigment;
		StringBuilder FakeEntryInvocation;
		StringBuilder FakeEntryInternals, FakeEntryExternals;
		int LastUsedSemanticIn = 0, LastUsedSemanticOut = 0;
		for (auto const& Argument : EntryPoint->Arguments)
		{
			CStr const ArgumentAccessType = Argument->AccsessType == GD_HLSL_ARGUMENT_IN ? "in " : "out";
			int& LastUsedSemantic = Argument->AccsessType == GD_HLSL_ARGUMENT_IN ? LastUsedSemanticIn : LastUsedSemanticOut;

			if (Argument->Type->Class == GD_HLSL_TYPE_CLASS_STRUCT)
			{
				if (Argument->AccsessType == GD_HLSL_ARGUMENT_IN)
				{
					FakeEntryInvocation.AppendFormat("%s(", Argument->Type->Name.CStr(), Argument->Name.CStr());
				}
				else
				{
					FakeEntryInvocation.AppendFormat("%s, ", Argument->Name.CStr());
					FakeEntryInternals.AppendFormat("\n\t%s %s;", Argument->Type->Name.CStr(), Argument->Name.CStr());
				}

				auto const Struct = static_cast<HLSLStruct const*>(Argument->Type);
				for (auto const& Definition : Struct->InnerDefinitions)
				{
					auto const StructField = static_cast<HLSLVariable const*>(Definition);
				//	auto const StructFieldSemantic = static_cast<HLSLSemantic const*>(StructField->Binding);
					FakeEntryExternals.AppendFormat("\nlayout(location = %d) %s %s Varying%s%s;", LastUsedSemantic
						, ArgumentAccessType, StructField->Type->Name.CStr(), Argument->Name.CStr(), StructField->Name.CStr());

					if (Argument->AccsessType == GD_HLSL_ARGUMENT_IN)
						FakeEntryInvocation.AppendFormat("Varying%s%s, ", Argument->Name.CStr(), StructField->Name.CStr());
					else
						FakeEntryAssigment.AppendFormat("\n\tVarying%s%s = %s.%s;", Argument->Name.CStr(), StructField->Name.CStr(), Argument->Name.CStr(), StructField->Name.CStr());
					LastUsedSemantic += 1;
				}

				if (Argument->AccsessType == GD_HLSL_ARGUMENT_IN)
				{
					//! @todo Refactor this awful code.
					*(FakeEntryInvocation.CStr() + FakeEntryInvocation.GetLength() - 2) = ')'; // Removing trailing comma.
					*(FakeEntryInvocation.CStr() + FakeEntryInvocation.GetLength() - 1) = ','; // Removing trailing space.
					FakeEntryInvocation.Append(' ');
				}
			}
			else
			{
				auto const ArgumentSemantic = static_cast<HLSLSemantic const*>(Argument->Binding);
				if (Argument->AccsessType == GD_HLSL_ARGUMENT_OUT)
				{
					if (ArgumentSemantic->Semantic == GD_HLSL_SEMANTIC_SV_Position)
						FakeEntryAssigment.AppendFormat("\n\tgl_Position = %s;", Argument->Name.CStr());
				}

				FakeEntryExternals.AppendFormat("\nlayout(location = %d) %s %s Varying%s;", LastUsedSemantic, ArgumentAccessType, Argument->Type->Name.CStr(), Argument->Name.CStr());
				FakeEntryInvocation.AppendFormat("Varying%s, ", Argument->Name.CStr());

				LastUsedSemantic += 1;
			}
		}

		//! @todo Refactor this awful code.
		*(FakeEntryInvocation.CStr() + FakeEntryInvocation.GetLength() - 2) = ')'; // Removing trailing comma.
		*(FakeEntryInvocation.CStr() + FakeEntryInvocation.GetLength() - 1) = ';'; // Removing trailing space.
		FakeEntryInvocation = Move(StringBuilder().AppendFormat("\n\t%s(%s", EntryPoint->Name.CStr(), FakeEntryInvocation.CStr()));

		if (EntryPoint->Type->Class == GD_HLSL_TYPE_CLASS_STRUCT)
		{
			FakeEntryInternals.AppendFormat("\n\t%s Ret;", EntryPoint->Type->Name.CStr());
			FakeEntryInvocation = Move(StringBuilder().AppendFormat("\n\tRet = %s", FakeEntryInvocation.CStr() + 2));

			HLSLStruct const* const ReturnStruct = static_cast<HLSLStruct const*>(EntryPoint->Type);
			for (auto const& Definition : ReturnStruct->InnerDefinitions)
			{
				HLSLVariable const* const ReturnStructField = static_cast<HLSLVariable const*>(Definition);
			//	HLSLSemantic const* const ReturnStructFieldSemantic = static_cast<HLSLSemantic const*>(ReturnStructField->Binding);
				FakeEntryExternals.AppendFormat("\nlayout(location = %d) out %s VaryingRet%s;", LastUsedSemanticOut, ReturnStructField->Type->Name.CStr(), ReturnStructField->Name.CStr());
				FakeEntryAssigment.AppendFormat("\n\tVaryingRet%s = Ret.%s;", ReturnStructField->Name.CStr(), ReturnStructField->Name.CStr());
				LastUsedSemanticOut += 1;
			}
		}
		else if (EntryPoint->Semantic != nullptr)
		{
			FakeEntryExternals.AppendFormat("\nlayout(location = %d) out %s VaryingRet;", LastUsedSemanticOut, EntryPoint->Name.CStr());
			FakeEntryInvocation = Move(StringBuilder().AppendFormat("\n\tVaryingRet = %s", FakeEntryInvocation.CStr() + 2));
		}

		Builder.AppendFormat("\n%s\n\nvoid main()\n{\n%s\n%s\n%s}\n", FakeEntryExternals.CStr()
			, FakeEntryInternals.CStr(), FakeEntryInvocation.CStr(), FakeEntryAssigment.CStr());
	}