/// <summary> /// Computes a hash <see cref="ObjectId"/> for the specified mixin. /// </summary> /// <param name="mixin">The mixin.</param> /// <param name="mixinParameters">The mixin parameters.</param> /// <returns>EffectObjectIds.</returns> public static ObjectId Compute(ShaderMixinSource mixin, EffectCompilerParameters effectCompilerParameters) { lock (generatorLock) { if (generator == null) { generator = new ShaderMixinObjectId(); } return(generator.ComputeInternal(mixin, effectCompilerParameters)); } }
private unsafe ObjectId ComputeInternal(ShaderMixinSource mixin, EffectCompilerParameters effectCompilerParameters) { // Write to memory stream memStream.Position = 0; writer.Write(EffectBytecode.MagicHeader); // Write the effect bytecode magic header writer.Write(mixin); writer.Write(effectCompilerParameters.Platform); writer.Write(effectCompilerParameters.Profile); writer.Write(effectCompilerParameters.Debug); writer.Write(effectCompilerParameters.OptimizationLevel); // Compute hash objectIdBuilder.Reset(); objectIdBuilder.Write((byte *)buffer, (int)memStream.Position); return(objectIdBuilder.ComputeHash()); }
public ShaderBytecodeResult Compile(string shaderSource, string entryPoint, ShaderStage stage, EffectCompilerParameters effectParameters, EffectReflection reflection, string sourceFilename = null) { var isDebug = effectParameters.Debug; var optimLevel = effectParameters.OptimizationLevel; var profile = effectParameters.Profile; var shaderModel = ShaderStageToString(stage) + "_" + ShaderProfileFromGraphicsProfile(profile); var shaderFlags = ShaderFlags.None; if (isDebug) { shaderFlags = ShaderFlags.Debug; } switch (optimLevel) { case 0: shaderFlags |= ShaderFlags.OptimizationLevel0; break; case 1: shaderFlags |= ShaderFlags.OptimizationLevel1; break; case 2: shaderFlags |= ShaderFlags.OptimizationLevel2; break; case 3: shaderFlags |= ShaderFlags.OptimizationLevel3; break; } SharpDX.Configuration.ThrowOnShaderCompileError = false; // Compile using D3DCompiler var compilationResult = SharpDX.D3DCompiler.ShaderBytecode.Compile(shaderSource, entryPoint, shaderModel, shaderFlags, EffectFlags.None, null, null, sourceFilename); var byteCodeResult = new ShaderBytecodeResult(); if (compilationResult.HasErrors || compilationResult.Bytecode == null) { // Log compilation errors byteCodeResult.Error(compilationResult.Message); } else { // TODO: Make this optional try { byteCodeResult.DisassembleText = compilationResult.Bytecode.Disassemble(); } catch (SharpDXException) { } // As effect bytecode binary can changed when having debug infos (with d3dcompiler_47), we are calculating a bytecodeId on the stripped version var rawData = compilationResult.Bytecode.Strip(StripFlags.CompilerStripDebugInformation | StripFlags.CompilerStripReflectionData); var bytecodeId = ObjectId.FromBytes(rawData); byteCodeResult.Bytecode = new ShaderBytecode(bytecodeId, compilationResult.Bytecode.Data) { Stage = stage }; // If compilation succeed, then we can update reflection. UpdateReflection(byteCodeResult.Bytecode, reflection, byteCodeResult); if (!string.IsNullOrEmpty(compilationResult.Message)) { byteCodeResult.Warning(compilationResult.Message); } } return(byteCodeResult); }
/// <summary> /// Converts the hlsl code into glsl and stores the result as plain text /// </summary> /// <param name="shaderSource">the hlsl shader</param> /// <param name="entryPoint">the entrypoint function name</param> /// <param name="stage">the shader pipeline stage</param> /// <param name="effectParameters"></param> /// <param name="reflection">the reflection gathered from the hlsl analysis</param> /// <param name="sourceFilename">the name of the source file</param> /// <returns></returns> public ShaderBytecodeResult Compile(string shaderSource, string entryPoint, ShaderStage stage, EffectCompilerParameters effectParameters, EffectReflection reflection, string sourceFilename = null) { var shaderBytecodeResult = new ShaderBytecodeResult(); byte[] rawData; GlslShaderPlatform shaderPlatform; int shaderVersion; switch (effectParameters.Platform) { case GraphicsPlatform.OpenGL: shaderPlatform = GlslShaderPlatform.OpenGL; shaderVersion = 420; break; case GraphicsPlatform.OpenGLES: shaderPlatform = GlslShaderPlatform.OpenGLES; shaderVersion = effectParameters.Profile >= GraphicsProfile.Level_10_0 ? 300 : 100; break; default: throw new ArgumentOutOfRangeException("effectParameters.Platform"); } var shader = Compile(shaderSource, entryPoint, stage, shaderPlatform, shaderVersion, shaderBytecodeResult, reflection, sourceFilename); if (shader == null) { return(shaderBytecodeResult); } if (effectParameters.Platform == GraphicsPlatform.OpenGLES) { // store both ES 2 and ES 3 on OpenGL ES platforms var shaderBytecodes = new ShaderLevelBytecode(); if (effectParameters.Profile >= GraphicsProfile.Level_10_0) { shaderBytecodes.DataES3 = shader; shaderBytecodes.DataES2 = null; } else { shaderBytecodes.DataES2 = shader; shaderBytecodes.DataES3 = Compile(shaderSource, entryPoint, stage, GlslShaderPlatform.OpenGLES, 300, shaderBytecodeResult, reflection, sourceFilename); } using (var stream = new MemoryStream()) { BinarySerialization.Write(stream, shaderBytecodes); #if !SILICONSTUDIO_RUNTIME_CORECLR rawData = stream.GetBuffer(); #else // FIXME: Manu: The call to "ToArray()" might be slower than "GetBuffer()" rawData = stream.ToArray(); #endif } } else { // store string on OpenGL platforms rawData = Encoding.ASCII.GetBytes(shader); } var bytecodeId = ObjectId.FromBytes(rawData); var bytecode = new ShaderBytecode(bytecodeId, rawData); bytecode.Stage = stage; shaderBytecodeResult.Bytecode = bytecode; return(shaderBytecodeResult); }
/// <summary> /// Converts the hlsl code into glsl and stores the result as plain text /// </summary> /// <param name="shaderSource">the hlsl shader</param> /// <param name="entryPoint">the entrypoint function name</param> /// <param name="stage">the shader pipeline stage</param> /// <param name="effectParameters"></param> /// <param name="reflection">the reflection gathered from the hlsl analysis</param> /// <param name="sourceFilename">the name of the source file</param> /// <returns></returns> public ShaderBytecodeResult Compile(string shaderSource, string entryPoint, ShaderStage stage, EffectCompilerParameters effectParameters, EffectReflection reflection, string sourceFilename = null) { var shaderBytecodeResult = new ShaderBytecodeResult(); byte[] rawData; var inputAttributeNames = new Dictionary <int, string>(); var resourceBindings = new Dictionary <string, int>(); GlslShaderPlatform shaderPlatform; int shaderVersion; switch (effectParameters.Platform) { case GraphicsPlatform.OpenGL: shaderPlatform = GlslShaderPlatform.OpenGL; shaderVersion = 410; break; case GraphicsPlatform.OpenGLES: shaderPlatform = GlslShaderPlatform.OpenGLES; shaderVersion = effectParameters.Profile >= GraphicsProfile.Level_10_0 ? 300 : 100; break; case GraphicsPlatform.Vulkan: shaderPlatform = GlslShaderPlatform.Vulkan; shaderVersion = 450; break; default: throw new ArgumentOutOfRangeException("effectParameters.Platform"); } var shader = Compile(shaderSource, entryPoint, stage, shaderPlatform, shaderVersion, shaderBytecodeResult, reflection, inputAttributeNames, resourceBindings, sourceFilename); if (shader == null) { return(shaderBytecodeResult); } if (effectParameters.Platform == GraphicsPlatform.OpenGLES) // TODO: Add check to run on android only. The current version breaks OpenGL ES on windows. { //TODO: Remove this ugly hack! if (shaderSource.Contains($"Texture2D XenkoInternal_TextureExt0") && shader.Contains("uniform sampler2D")) { if (shaderPlatform != GlslShaderPlatform.OpenGLES || shaderVersion != 300) { throw new Exception("Invalid GLES platform or version: require OpenGLES 300"); } shader = shader.Replace("uniform sampler2D", "uniform samplerExternalOES"); shader = shader.Replace("#version 300 es", "#version 300 es\n#extension GL_OES_EGL_image_external_essl3 : require"); } } if (effectParameters.Platform == GraphicsPlatform.OpenGLES) { // store both ES 2 and ES 3 on OpenGL ES platforms var shaderBytecodes = new ShaderLevelBytecode(); if (effectParameters.Profile >= GraphicsProfile.Level_10_0) { shaderBytecodes.DataES3 = shader; shaderBytecodes.DataES2 = null; } else { shaderBytecodes.DataES2 = shader; shaderBytecodes.DataES3 = Compile(shaderSource, entryPoint, stage, GlslShaderPlatform.OpenGLES, 300, shaderBytecodeResult, reflection, inputAttributeNames, resourceBindings, sourceFilename); } using (var stream = new MemoryStream()) { BinarySerialization.Write(stream, shaderBytecodes); rawData = stream.GetBuffer(); } } else if (effectParameters.Platform == GraphicsPlatform.Vulkan) { string inputFileExtension; switch (stage) { case ShaderStage.Vertex: inputFileExtension = ".vert"; break; case ShaderStage.Pixel: inputFileExtension = ".frag"; break; case ShaderStage.Geometry: inputFileExtension = ".geom"; break; case ShaderStage.Domain: inputFileExtension = ".tese"; break; case ShaderStage.Hull: inputFileExtension = ".tesc"; break; case ShaderStage.Compute: inputFileExtension = ".comp"; break; default: shaderBytecodeResult.Error("Unknown shader profile"); return(shaderBytecodeResult); } var inputFileName = Path.ChangeExtension(Path.GetTempFileName(), inputFileExtension); var outputFileName = Path.ChangeExtension(inputFileName, ".spv"); // Write shader source to disk File.WriteAllBytes(inputFileName, Encoding.ASCII.GetBytes(shader)); // Run shader compiler var filename = Platform.Type == PlatformType.Windows ? "glslangValidator.exe" : "glslangValidator"; ShellHelper.RunProcessAndRedirectToLogger(filename, $"-V -o {outputFileName} {inputFileName}", null, shaderBytecodeResult); if (!File.Exists(outputFileName)) { shaderBytecodeResult.Error("Failed to generate SPIR-V from GLSL"); return(shaderBytecodeResult); } // Read compiled shader var shaderBytecodes = new ShaderInputBytecode { InputAttributeNames = inputAttributeNames, ResourceBindings = resourceBindings, Data = File.ReadAllBytes(outputFileName), }; using (var stream = new MemoryStream()) { BinarySerialization.Write(stream, shaderBytecodes); rawData = stream.ToArray(); } // Cleanup temp files File.Delete(inputFileName); File.Delete(outputFileName); } else { // store string on OpenGL platforms rawData = Encoding.UTF8.GetBytes(shader); } var bytecodeId = ObjectId.FromBytes(rawData); var bytecode = new ShaderBytecode(bytecodeId, rawData); bytecode.Stage = stage; shaderBytecodeResult.Bytecode = bytecode; return(shaderBytecodeResult); }
/// <summary> /// Converts the hlsl code into glsl and stores the result as plain text /// </summary> /// <param name="shaderSource">the hlsl shader</param> /// <param name="entryPoint">the entrypoint function name</param> /// <param name="stage">the shader pipeline stage</param> /// <param name="effectParameters"></param> /// <param name="reflection">the reflection gathered from the hlsl analysis</param> /// <param name="sourceFilename">the name of the source file</param> /// <returns></returns> public ShaderBytecodeResult Compile(string shaderSource, string entryPoint, ShaderStage stage, EffectCompilerParameters effectParameters, EffectReflection reflection, string sourceFilename = null) { var shaderBytecodeResult = new ShaderBytecodeResult(); byte[] rawData; var inputAttributeNames = new Dictionary <int, string>(); var resourceBindings = new Dictionary <string, int>(); GlslShaderPlatform shaderPlatform; int shaderVersion; switch (effectParameters.Platform) { case GraphicsPlatform.OpenGL: shaderPlatform = GlslShaderPlatform.OpenGL; shaderVersion = 420; break; case GraphicsPlatform.OpenGLES: shaderPlatform = GlslShaderPlatform.OpenGLES; shaderVersion = effectParameters.Profile >= GraphicsProfile.Level_10_0 ? 300 : 100; break; case GraphicsPlatform.Vulkan: shaderPlatform = GlslShaderPlatform.Vulkan; shaderVersion = 450; break; default: throw new ArgumentOutOfRangeException("effectParameters.Platform"); } var shader = Compile(shaderSource, entryPoint, stage, shaderPlatform, shaderVersion, shaderBytecodeResult, reflection, inputAttributeNames, resourceBindings, sourceFilename); if (shader == null) { return(shaderBytecodeResult); } if (effectParameters.Platform == GraphicsPlatform.OpenGLES) { // store both ES 2 and ES 3 on OpenGL ES platforms var shaderBytecodes = new ShaderLevelBytecode(); if (effectParameters.Profile >= GraphicsProfile.Level_10_0) { shaderBytecodes.DataES3 = shader; shaderBytecodes.DataES2 = null; } else { shaderBytecodes.DataES2 = shader; shaderBytecodes.DataES3 = Compile(shaderSource, entryPoint, stage, GlslShaderPlatform.OpenGLES, 300, shaderBytecodeResult, reflection, inputAttributeNames, resourceBindings, sourceFilename); } using (var stream = new MemoryStream()) { BinarySerialization.Write(stream, shaderBytecodes); #if !SILICONSTUDIO_RUNTIME_CORECLR rawData = stream.GetBuffer(); #else // FIXME: Manu: The call to "ToArray()" might be slower than "GetBuffer()" rawData = stream.ToArray(); #endif } } else if (effectParameters.Platform == GraphicsPlatform.Vulkan) { string inputFileExtension; switch (stage) { case ShaderStage.Vertex: inputFileExtension = ".vert"; break; case ShaderStage.Pixel: inputFileExtension = ".frag"; break; case ShaderStage.Geometry: inputFileExtension = ".geom"; break; case ShaderStage.Domain: inputFileExtension = ".tese"; break; case ShaderStage.Hull: inputFileExtension = ".tesc"; break; case ShaderStage.Compute: inputFileExtension = ".comp"; break; default: shaderBytecodeResult.Error("Unknown shader profile"); return(shaderBytecodeResult); } var inputFileName = Path.ChangeExtension(Path.GetTempFileName(), inputFileExtension); var outputFileName = Path.ChangeExtension(inputFileName, ".spv"); // Write shader source to disk File.WriteAllBytes(inputFileName, Encoding.ASCII.GetBytes(shader)); // Run shader compiler var process = new Process { StartInfo = { FileName = "glslangValidator.exe", Arguments = $"-V -s -o {outputFileName} {inputFileName}", RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, CreateNoWindow = true } }; process.Start(); process.WaitForExit(); if (!File.Exists(outputFileName)) { shaderBytecodeResult.Error("Failed to generate SPIR-V from GLSL"); return(shaderBytecodeResult); } // Read compiled shader var shaderBytecodes = new ShaderInputBytecode { InputAttributeNames = inputAttributeNames, ResourceBindings = resourceBindings, Data = File.ReadAllBytes(outputFileName), }; using (var stream = new MemoryStream()) { BinarySerialization.Write(stream, shaderBytecodes); rawData = stream.ToArray(); } // Cleanup temp files File.Delete(inputFileName); File.Delete(outputFileName); } else { // store string on OpenGL platforms rawData = Encoding.ASCII.GetBytes(shader); } var bytecodeId = ObjectId.FromBytes(rawData); var bytecode = new ShaderBytecode(bytecodeId, rawData); bytecode.Stage = stage; shaderBytecodeResult.Bytecode = bytecode; return(shaderBytecodeResult); }
public ShaderBytecodeResult Compile(string shaderSource, string entryPoint, ShaderStage stage, EffectCompilerParameters effectParameters, EffectReflection reflection, string sourceFilename = null) { var isDebug = effectParameters.Debug; var optimLevel = effectParameters.OptimizationLevel; var profile = effectParameters.Profile; var shaderModel = ShaderStageToString(stage) + "_" + ShaderProfileFromGraphicsProfile(profile); var shaderFlags = ShaderFlags.None; if (isDebug) { shaderFlags = ShaderFlags.Debug; } switch (optimLevel) { case 0: shaderFlags |= ShaderFlags.OptimizationLevel0; break; case 1: shaderFlags |= ShaderFlags.OptimizationLevel1; break; case 2: shaderFlags |= ShaderFlags.OptimizationLevel2; break; case 3: shaderFlags |= ShaderFlags.OptimizationLevel3; break; } SharpDX.Configuration.ThrowOnShaderCompileError = false; // Compile using D3DCompiler var compilationResult = SharpDX.D3DCompiler.ShaderBytecode.Compile(shaderSource, entryPoint, shaderModel, shaderFlags, EffectFlags.None, null, null, sourceFilename); var byteCodeResult = new ShaderBytecodeResult(); if (compilationResult.HasErrors || compilationResult.Bytecode == null) { // Log compilation errors byteCodeResult.Error(compilationResult.Message); } else { // TODO: Make this optional try { byteCodeResult.DisassembleText = compilationResult.Bytecode.Disassemble(); } catch (SharpDXException) { } // As effect bytecode binary can changed when having debug infos (with d3dcompiler_47), we are calculating a bytecodeId on the stripped version var rawData = compilationResult.Bytecode.Strip(StripFlags.CompilerStripDebugInformation | StripFlags.CompilerStripReflectionData); var bytecodeId = ObjectId.FromBytes(rawData); byteCodeResult.Bytecode = new ShaderBytecode(bytecodeId, compilationResult.Bytecode.Data) { Stage = stage }; // If compilation succeed, then we can update reflection. UpdateReflection(byteCodeResult.Bytecode, reflection, byteCodeResult); if (!string.IsNullOrEmpty(compilationResult.Message)) { byteCodeResult.Warning(compilationResult.Message); } } return byteCodeResult; }
/// <summary> /// Converts the hlsl code into glsl and stores the result as plain text /// </summary> /// <param name="shaderSource">the hlsl shader</param> /// <param name="entryPoint">the entrypoint function name</param> /// <param name="stage">the shader pipeline stage</param> /// <param name="effectParameters"></param> /// <param name="reflection">the reflection gathered from the hlsl analysis</param> /// <param name="sourceFilename">the name of the source file</param> /// <returns></returns> public ShaderBytecodeResult Compile(string shaderSource, string entryPoint, ShaderStage stage, EffectCompilerParameters effectParameters, EffectReflection reflection, string sourceFilename = null) { var isOpenGLES = effectParameters.Platform == GraphicsPlatform.OpenGLES; var isOpenGLES3 = effectParameters.Profile >= GraphicsProfile.Level_10_0; var shaderBytecodeResult = new ShaderBytecodeResult(); byte[] rawData; var shader = Compile(shaderSource, entryPoint, stage, isOpenGLES, isOpenGLES3, shaderBytecodeResult, reflection, sourceFilename); if (shader == null) { return(shaderBytecodeResult); } if (isOpenGLES) { // store both ES 2 and ES 3 on OpenGL ES platforms var shaderBytecodes = new ShaderLevelBytecode(); if (isOpenGLES3) { shaderBytecodes.DataES3 = shader; shaderBytecodes.DataES2 = null; } else { shaderBytecodes.DataES2 = shader; shaderBytecodes.DataES3 = Compile(shaderSource, entryPoint, stage, true, true, shaderBytecodeResult, reflection, sourceFilename); } using (var stream = new MemoryStream()) { BinarySerialization.Write(stream, shaderBytecodes); #if !SILICONSTUDIO_RUNTIME_CORECLR rawData = stream.GetBuffer(); #else // FIXME: Manu: The call to "ToArray()" might be slower than "GetBuffer()" rawData = stream.ToArray(); #endif } } else { // store string on OpenGL platforms rawData = Encoding.ASCII.GetBytes(shader); } var bytecodeId = ObjectId.FromBytes(rawData); var bytecode = new ShaderBytecode(bytecodeId, rawData); bytecode.Stage = stage; shaderBytecodeResult.Bytecode = bytecode; return(shaderBytecodeResult); }
/// <summary> /// Converts the hlsl code into glsl and stores the result as plain text /// </summary> /// <param name="shaderSource">the hlsl shader</param> /// <param name="entryPoint">the entrypoint function name</param> /// <param name="stage">the shader pipeline stage</param> /// <param name="effectParameters"></param> /// <param name="reflection">the reflection gathered from the hlsl analysis</param> /// <param name="sourceFilename">the name of the source file</param> /// <returns></returns> public ShaderBytecodeResult Compile(string shaderSource, string entryPoint, ShaderStage stage, EffectCompilerParameters effectParameters, EffectReflection reflection, string sourceFilename = null) { var shaderBytecodeResult = new ShaderBytecodeResult(); byte[] rawData; GlslShaderPlatform shaderPlatform; int shaderVersion; switch (effectParameters.Platform) { case GraphicsPlatform.OpenGL: shaderPlatform = GlslShaderPlatform.OpenGL; shaderVersion = 420; break; case GraphicsPlatform.OpenGLES: shaderPlatform = GlslShaderPlatform.OpenGLES; shaderVersion = effectParameters.Profile >= GraphicsProfile.Level_10_0 ? 300 : 100; break; default: throw new ArgumentOutOfRangeException("effectParameters.Platform"); } var shader = Compile(shaderSource, entryPoint, stage, shaderPlatform, shaderVersion, shaderBytecodeResult, reflection, sourceFilename); if (shader == null) return shaderBytecodeResult; if (effectParameters.Platform == GraphicsPlatform.OpenGLES) { // store both ES 2 and ES 3 on OpenGL ES platforms var shaderBytecodes = new ShaderLevelBytecode(); if (effectParameters.Profile >= GraphicsProfile.Level_10_0) { shaderBytecodes.DataES3 = shader; shaderBytecodes.DataES2 = null; } else { shaderBytecodes.DataES2 = shader; shaderBytecodes.DataES3 = Compile(shaderSource, entryPoint, stage, GlslShaderPlatform.OpenGLES, 300, shaderBytecodeResult, reflection, sourceFilename); } using (var stream = new MemoryStream()) { BinarySerialization.Write(stream, shaderBytecodes); #if !SILICONSTUDIO_RUNTIME_CORECLR rawData = stream.GetBuffer(); #else // FIXME: Manu: The call to "ToArray()" might be slower than "GetBuffer()" rawData = stream.ToArray(); #endif } } else { // store string on OpenGL platforms rawData = Encoding.ASCII.GetBytes(shader); } var bytecodeId = ObjectId.FromBytes(rawData); var bytecode = new ShaderBytecode(bytecodeId, rawData); bytecode.Stage = stage; shaderBytecodeResult.Bytecode = bytecode; return shaderBytecodeResult; }
/// <summary> /// Converts the hlsl code into glsl and stores the result as plain text /// </summary> /// <param name="shaderSource">the hlsl shader</param> /// <param name="entryPoint">the entrypoint function name</param> /// <param name="stage">the shader pipeline stage</param> /// <param name="effectParameters"></param> /// <param name="reflection">the reflection gathered from the hlsl analysis</param> /// <param name="sourceFilename">the name of the source file</param> /// <returns></returns> public ShaderBytecodeResult Compile(string shaderSource, string entryPoint, ShaderStage stage, EffectCompilerParameters effectParameters, EffectReflection reflection, string sourceFilename = null) { var shaderBytecodeResult = new ShaderBytecodeResult(); byte[] rawData; var inputAttributeNames = new Dictionary <int, string>(); var resourceBindings = new Dictionary <string, int>(); GlslShaderPlatform shaderPlatform; int shaderVersion; switch (effectParameters.Platform) { case GraphicsPlatform.Vulkan: shaderPlatform = GlslShaderPlatform.Vulkan; shaderVersion = 450; break; default: throw new ArgumentOutOfRangeException("effectParameters.Platform"); } var shader = Compile(shaderSource, entryPoint, stage, shaderPlatform, shaderVersion, shaderBytecodeResult, reflection, inputAttributeNames, resourceBindings, sourceFilename); if (shader == null) { return(shaderBytecodeResult); } if (effectParameters.Platform == GraphicsPlatform.Vulkan) { string inputFileExtension; switch (stage) { case ShaderStage.Vertex: inputFileExtension = ".vert"; break; case ShaderStage.Pixel: inputFileExtension = ".frag"; break; case ShaderStage.Geometry: inputFileExtension = ".geom"; break; case ShaderStage.Domain: inputFileExtension = ".tese"; break; case ShaderStage.Hull: inputFileExtension = ".tesc"; break; case ShaderStage.Compute: inputFileExtension = ".comp"; break; default: shaderBytecodeResult.Error("Unknown shader profile"); return(shaderBytecodeResult); } var inputFileName = Path.ChangeExtension(Path.GetTempFileName(), inputFileExtension); var outputFileName = Path.ChangeExtension(inputFileName, ".spv"); // Write shader source to disk File.WriteAllBytes(inputFileName, Encoding.ASCII.GetBytes(shader)); // Run shader compiler var filename = Platform.Type == PlatformType.Windows ? "glslangValidator.exe" : "glslangValidator"; ShellHelper.RunProcessAndRedirectToLogger(filename, $"-V -o {outputFileName} {inputFileName}", null, shaderBytecodeResult); if (!File.Exists(outputFileName)) { shaderBytecodeResult.Error("Failed to generate SPIR-V from GLSL"); return(shaderBytecodeResult); } // Read compiled shader var shaderBytecodes = new ShaderInputBytecode { InputAttributeNames = inputAttributeNames, ResourceBindings = resourceBindings, Data = File.ReadAllBytes(outputFileName), }; using (var stream = new MemoryStream()) { BinarySerialization.Write(stream, shaderBytecodes); rawData = stream.ToArray(); } // Cleanup temp files File.Delete(inputFileName); File.Delete(outputFileName); } else { // store string on OpenGL platforms rawData = Encoding.UTF8.GetBytes(shader); } var bytecodeId = ObjectId.FromBytes(rawData); var bytecode = new ShaderBytecode(bytecodeId, rawData); bytecode.Stage = stage; shaderBytecodeResult.Bytecode = bytecode; return(shaderBytecodeResult); }
/// <summary> /// Converts the hlsl code into glsl and stores the result as plain text /// </summary> /// <param name="shaderSource">the hlsl shader</param> /// <param name="entryPoint">the entrypoint function name</param> /// <param name="stage">the shader pipeline stage</param> /// <param name="effectParameters"></param> /// <param name="reflection">the reflection gathered from the hlsl analysis</param> /// <param name="sourceFilename">the name of the source file</param> /// <returns></returns> public ShaderBytecodeResult Compile(string shaderSource, string entryPoint, ShaderStage stage, EffectCompilerParameters effectParameters, EffectReflection reflection, string sourceFilename = null) { var shaderBytecodeResult = new ShaderBytecodeResult(); byte[] rawData; var inputAttributeNames = new Dictionary<int, string>(); var resourceBindings = new Dictionary<string, int>(); GlslShaderPlatform shaderPlatform; int shaderVersion; switch (effectParameters.Platform) { case GraphicsPlatform.OpenGL: shaderPlatform = GlslShaderPlatform.OpenGL; shaderVersion = 410; break; case GraphicsPlatform.OpenGLES: shaderPlatform = GlslShaderPlatform.OpenGLES; shaderVersion = effectParameters.Profile >= GraphicsProfile.Level_10_0 ? 300 : 100; break; case GraphicsPlatform.Vulkan: shaderPlatform = GlslShaderPlatform.Vulkan; shaderVersion = 450; break; default: throw new ArgumentOutOfRangeException("effectParameters.Platform"); } var shader = Compile(shaderSource, entryPoint, stage, shaderPlatform, shaderVersion, shaderBytecodeResult, reflection, inputAttributeNames, resourceBindings, sourceFilename); if (shader == null) return shaderBytecodeResult; if (effectParameters.Platform == GraphicsPlatform.OpenGLES) { // store both ES 2 and ES 3 on OpenGL ES platforms var shaderBytecodes = new ShaderLevelBytecode(); if (effectParameters.Profile >= GraphicsProfile.Level_10_0) { shaderBytecodes.DataES3 = shader; shaderBytecodes.DataES2 = null; } else { shaderBytecodes.DataES2 = shader; shaderBytecodes.DataES3 = Compile(shaderSource, entryPoint, stage, GlslShaderPlatform.OpenGLES, 300, shaderBytecodeResult, reflection, inputAttributeNames, resourceBindings, sourceFilename); } using (var stream = new MemoryStream()) { BinarySerialization.Write(stream, shaderBytecodes); #if !SILICONSTUDIO_RUNTIME_CORECLR && !SILICONSTUDIO_PLATFORM_UWP rawData = stream.GetBuffer(); #else // FIXME: Manu: The call to "ToArray()" might be slower than "GetBuffer()" rawData = stream.ToArray(); #endif } } #if !SILICONSTUDIO_RUNTIME_CORECLR && !SILICONSTUDIO_PLATFORM_UWP else if (effectParameters.Platform == GraphicsPlatform.Vulkan) { string inputFileExtension; switch (stage) { case ShaderStage.Vertex: inputFileExtension = ".vert"; break; case ShaderStage.Pixel: inputFileExtension = ".frag"; break; case ShaderStage.Geometry: inputFileExtension = ".geom"; break; case ShaderStage.Domain: inputFileExtension = ".tese"; break; case ShaderStage.Hull: inputFileExtension = ".tesc"; break; case ShaderStage.Compute: inputFileExtension = ".comp"; break; default: shaderBytecodeResult.Error("Unknown shader profile"); return shaderBytecodeResult; } var inputFileName = Path.ChangeExtension(Path.GetTempFileName(), inputFileExtension); var outputFileName = Path.ChangeExtension(inputFileName, ".spv"); // Write shader source to disk File.WriteAllBytes(inputFileName, Encoding.ASCII.GetBytes(shader)); // Run shader compiler var filename = Platform.Type == PlatformType.Windows ? "glslangValidator.exe" : "glslangValidator"; ShellHelper.RunProcessAndRedirectToLogger(filename, $"-V -o {outputFileName} {inputFileName}", null, shaderBytecodeResult); if (!File.Exists(outputFileName)) { shaderBytecodeResult.Error("Failed to generate SPIR-V from GLSL"); return shaderBytecodeResult; } // Read compiled shader var shaderBytecodes = new ShaderInputBytecode { InputAttributeNames = inputAttributeNames, ResourceBindings = resourceBindings, Data = File.ReadAllBytes(outputFileName), }; using (var stream = new MemoryStream()) { BinarySerialization.Write(stream, shaderBytecodes); rawData = stream.ToArray(); } // Cleanup temp files File.Delete(inputFileName); File.Delete(outputFileName); } #endif else { // store string on OpenGL platforms rawData = Encoding.UTF8.GetBytes(shader); } var bytecodeId = ObjectId.FromBytes(rawData); var bytecode = new ShaderBytecode(bytecodeId, rawData); bytecode.Stage = stage; shaderBytecodeResult.Bytecode = bytecode; return shaderBytecodeResult; }