Exemplo n.º 1
0
        /// <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="compilerParameters"></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, ShaderMixinParameters compilerParameters, EffectReflection reflection, string sourceFilename = null)
        {
            var isOpenGLES           = compilerParameters.Get(CompilerParameters.GraphicsPlatformKey) == GraphicsPlatform.OpenGLES;
            var isOpenGLES3          = compilerParameters.Get(CompilerParameters.GraphicsProfileKey) >= GraphicsProfile.Level_10_0;
            var shaderBytecodeResult = new ShaderBytecodeResult();

            byte[] rawData;

            var shader = Compile(shaderSource, entryPoint, stage, isOpenGLES, isOpenGLES3, shaderBytecodeResult, 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, 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);
        }
Exemplo n.º 2
0
        /// <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="compilerParameters"></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, ShaderMixinParameters compilerParameters, EffectReflection reflection, string sourceFilename = null)
        {
            var isOpenGLES = compilerParameters.Get(CompilerParameters.GraphicsPlatformKey) == GraphicsPlatform.OpenGLES;
            var isOpenGLES3 = compilerParameters.Get(CompilerParameters.GraphicsProfileKey) >= GraphicsProfile.Level_10_0;
            var shaderBytecodeResult = new ShaderBytecodeResult();
            byte[] rawData;

            var shader = Compile(shaderSource, entryPoint, stage, isOpenGLES, isOpenGLES3, shaderBytecodeResult, 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, 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;
        }
Exemplo n.º 3
0
        public ShaderBytecodeResult Compile(string shaderSource, string entryPoint, ShaderStage stage, ShaderMixinParameters compilerParameters, EffectReflection reflection, string sourceFilename = null)
        {
            var isDebug = compilerParameters.Get(CompilerParameters.DebugKey);
            var profile = compilerParameters.Get(CompilerParameters.GraphicsProfileKey);

            var shaderModel = ShaderStageToString(stage) + "_" + ShaderProfileFromGraphicsProfile(profile);

            var shaderFlags = ShaderFlags.None;

            if (isDebug)
            {
                shaderFlags = ShaderFlags.OptimizationLevel0 | ShaderFlags.Debug;
            }

            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
            {
                // 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);
        }
Exemplo n.º 4
0
        public ShaderBytecodeResult Compile(string shaderSource, string entryPoint, ShaderStage stage, ShaderMixinParameters compilerParameters, EffectReflection reflection, string sourceFilename = null)
        {
            var isDebug = compilerParameters.Get(CompilerParameters.DebugKey);
            var profile = compilerParameters.Get(CompilerParameters.GraphicsProfileKey);
            
            var shaderModel = ShaderStageToString(stage) + "_" + ShaderProfileFromGraphicsProfile(profile);

            var shaderFlags = ShaderFlags.None;
            if (isDebug)
            {
                shaderFlags = ShaderFlags.OptimizationLevel0 | ShaderFlags.Debug;
            }

            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)
            {
                // Log compilation errors
                byteCodeResult.Error(compilationResult.Message);
            }
            else
            {
                // 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;
        }
Exemplo n.º 5
0
        public override EffectBytecode Compile(ShaderMixinSource shaderMixinSource, string fullEffectName, ShaderMixinParameters compilerParameters, HashSet <string> modifiedShaders, HashSet <string> recentlyModifiedShaders, LoggerResult log)
        {
            // Load D3D compiler dll
            // Note: No lock, it's probably fine if it gets called from multiple threads at the same time.
            if (Platform.IsWindowsDesktop && !d3dcompilerLoaded)
            {
                NativeLibrary.PreloadLibrary("d3dcompiler_47.dll");
                d3dcompilerLoaded = true;
            }

            // Make a copy of shaderMixinSource. Use deep clone since shaderMixinSource can be altered during compilation (e.g. macros)
            var shaderMixinSourceCopy = new ShaderMixinSource();

            shaderMixinSourceCopy.DeepCloneFrom(shaderMixinSource);

            shaderMixinSource = shaderMixinSourceCopy;

            // Generate platform-specific macros
            var platform = compilerParameters.Get(CompilerParameters.GraphicsPlatformKey);

            switch (platform)
            {
            case GraphicsPlatform.Direct3D11:
                shaderMixinSource.AddMacro("SILICONSTUDIO_PARADOX_GRAPHICS_API_DIRECT3D", 1);
                shaderMixinSource.AddMacro("SILICONSTUDIO_PARADOX_GRAPHICS_API_DIRECT3D11", 1);
                break;

            case GraphicsPlatform.OpenGL:
                shaderMixinSource.AddMacro("SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGL", 1);
                shaderMixinSource.AddMacro("SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGLCORE", 1);
                break;

            case GraphicsPlatform.OpenGLES:
                shaderMixinSource.AddMacro("SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGL", 1);
                shaderMixinSource.AddMacro("SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGLES", 1);
                break;

            default:
                throw new NotSupportedException();
            }

            // Generate the AST from the mixin description
            if (shaderMixinParser == null)
            {
                shaderMixinParser = new ShaderMixinParser();
                shaderMixinParser.SourceManager.LookupDirectoryList = SourceDirectories; // TODO: temp
                shaderMixinParser.SourceManager.UrlToFilePath       = UrlToFilePath;     // TODO: temp
            }

            if (recentlyModifiedShaders != null && recentlyModifiedShaders.Count > 0)
            {
                shaderMixinParser.DeleteObsoleteCache(GetShaderNames(recentlyModifiedShaders));
                recentlyModifiedShaders.Clear();
            }
            var parsingResult = shaderMixinParser.Parse(shaderMixinSource, shaderMixinSource.Macros.ToArray(), modifiedShaders);

            // Copy log from parser results to output
            CopyLogs(parsingResult, log);

            // Return directly if there are any errors
            if (parsingResult.HasErrors)
            {
                return(null);
            }

            // Convert the AST to HLSL
            var writer = new SiliconStudio.Shaders.Writer.Hlsl.HlslWriter {
                EnablePreprocessorLine = false
            };

            writer.Visit(parsingResult.Shader);
            var shaderSourceText = writer.Text;

            // -------------------------------------------------------
            // Save shader log
            // TODO: TEMP code to allow debugging generated shaders on Windows Desktop
#if SILICONSTUDIO_PLATFORM_WINDOWS_DESKTOP
            var shaderId = ObjectId.FromBytes(Encoding.UTF8.GetBytes(shaderSourceText));

            var logDir = "log";
            if (!Directory.Exists(logDir))
            {
                Directory.CreateDirectory(logDir);
            }
            var shaderSourceFilename = Path.Combine(logDir, "shader_" + shaderId);
            lock (WriterLock) // protect write in case the same shader is created twice
            {
                if (!File.Exists(shaderSourceFilename))
                {
                    var builder = new StringBuilder();
                    builder.AppendLine("/***** Used Parameters *****");
                    builder.Append(" * EffectName: ");
                    builder.AppendLine(fullEffectName ?? "");
                    WriteParameters(builder, compilerParameters, 0, false);
                    builder.AppendLine(" ***************************/");
                    builder.Append(shaderSourceText);
                    File.WriteAllText(shaderSourceFilename, builder.ToString());
                }
            }
#endif
            // -------------------------------------------------------

            var bytecode = new EffectBytecode {
                Reflection = parsingResult.Reflection, HashSources = parsingResult.HashSources
            };

            // Select the correct backend compiler
            IShaderCompiler compiler;
            switch (platform)
            {
            case GraphicsPlatform.Direct3D11:
                compiler = new Direct3D.ShaderCompiler();
                break;

            case GraphicsPlatform.OpenGL:
            case GraphicsPlatform.OpenGLES:
                compiler = new OpenGL.ShaderCompiler();
                break;

            default:
                throw new NotSupportedException();
            }

            var shaderStageBytecodes = new List <ShaderBytecode>();

            foreach (var stageBinding in parsingResult.EntryPoints)
            {
                // Compile
                var result = compiler.Compile(shaderSourceText, stageBinding.Value, stageBinding.Key, compilerParameters, bytecode.Reflection, shaderSourceFilename);
                result.CopyTo(log);

                if (result.HasErrors)
                {
                    continue;
                }

                // -------------------------------------------------------
                // Append bytecode id to shader log
#if SILICONSTUDIO_PLATFORM_WINDOWS_DESKTOP
                lock (WriterLock) // protect write in case the same shader is created twice
                {
                    if (File.Exists(shaderSourceFilename))
                    {
                        // Append at the end of the shader the bytecodes Id
                        File.AppendAllText(shaderSourceFilename, "\n// {0} {1}".ToFormat(stageBinding.Key, result.Bytecode.Id));
                    }
                }
#endif
                // -------------------------------------------------------

                shaderStageBytecodes.Add(result.Bytecode);

                // When this is a compute shader, there is no need to scan other stages
                if (stageBinding.Key == ShaderStage.Compute)
                {
                    break;
                }
            }

            // Get the current time of compilation
            bytecode.Time = DateTime.Now;

            // In case of Direct3D, we can safely remove reflection data as it is entirely resolved at compile time.
            if (platform == GraphicsPlatform.Direct3D11)
            {
                CleanupReflection(bytecode.Reflection);
            }

            bytecode.Stages = shaderStageBytecodes.ToArray();
            return(bytecode);
        }
Exemplo n.º 6
0
        /// <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="compilerParameters"></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, ShaderMixinParameters compilerParameters, EffectReflection reflection, string sourceFilename = null)
        {
            var isOpenGLES           = compilerParameters.Get(CompilerParameters.GraphicsPlatformKey) == GraphicsPlatform.OpenGLES;
            var shaderBytecodeResult = new ShaderBytecodeResult();


            PipelineStage pipelineStage = PipelineStage.None;

            switch (stage)
            {
            case ShaderStage.Vertex:
                pipelineStage = PipelineStage.Vertex;
                break;

            case ShaderStage.Pixel:
                pipelineStage = PipelineStage.Pixel;
                break;

            case ShaderStage.Geometry:
                shaderBytecodeResult.Error("Geometry stage can't be converted to OpenGL. Only Vertex and Pixel shaders are supported");
                break;

            case ShaderStage.Hull:
                shaderBytecodeResult.Error("Hull stage can't be converted to OpenGL. Only Vertex and Pixel shaders are supported");
                break;

            case ShaderStage.Domain:
                shaderBytecodeResult.Error("Domain stage can't be converted to OpenGL. Only Vertex and Pixel shaders are supported");
                break;

            case ShaderStage.Compute:
                shaderBytecodeResult.Error("Compute stage can't be converted to OpenGL. Only Vertex and Pixel shaders are supported");
                break;

            default:
                shaderBytecodeResult.Error("Unknown shader profile.");
                break;
            }

            if (shaderBytecodeResult.HasErrors)
            {
                return(shaderBytecodeResult);
            }

            // Convert from HLSL to GLSL
            // Note that for now we parse from shader as a string, but we could simply clone effectPass.Shader to avoid multiple parsing.
            var glslConvertor = new ShaderConverter(isOpenGLES);
            var glslShader    = glslConvertor.Convert(shaderSource, entryPoint, pipelineStage, sourceFilename, shaderBytecodeResult);

            // Add std140 layout
            foreach (var constantBuffer in glslShader.Declarations.OfType <ConstantBuffer>())
            {
                constantBuffer.Qualifiers |= new LayoutQualifier(new LayoutKeyValue("std140"));
            }

            // Output the result
            var glslShaderWriter = new HlslToGlslWriter();

            if (isOpenGLES)
            {
                glslShaderWriter.TrimFloatSuffix       = true;
                glslShaderWriter.GenerateUniformBlocks = false;
                foreach (var variable in glslShader.Declarations.OfType <Variable>())
                {
                    if (variable.Qualifiers.Contains(ParameterQualifier.In))
                    {
                        variable.Qualifiers.Values.Remove(ParameterQualifier.In);
                        // "in" becomes "attribute" in VS, "varying" in other stages
                        variable.Qualifiers.Values.Add(
                            pipelineStage == PipelineStage.Vertex
                                ? global::SiliconStudio.Shaders.Ast.Glsl.ParameterQualifier.Attribute
                                : global::SiliconStudio.Shaders.Ast.Glsl.ParameterQualifier.Varying);
                    }
                    if (variable.Qualifiers.Contains(ParameterQualifier.Out))
                    {
                        variable.Qualifiers.Values.Remove(ParameterQualifier.Out);
                        variable.Qualifiers.Values.Add(global::SiliconStudio.Shaders.Ast.Glsl.ParameterQualifier.Varying);
                    }
                }
            }

            // Write shader
            glslShaderWriter.Visit(glslShader);

            // Build shader source
            var glslShaderCode = new StringBuilder();

            // Append some header depending on target
            if (!isOpenGLES)
            {
                glslShaderCode
                .AppendLine("#version 420")
                .AppendLine();

                if (pipelineStage == PipelineStage.Pixel)
                {
                    glslShaderCode
                    .AppendLine("out vec4 gl_FragData[1];")
                    .AppendLine();
                }
            }

            if (isOpenGLES)
            {
                if (pipelineStage == PipelineStage.Pixel)
                {
                    glslShaderCode
                    .AppendLine("precision highp float;")
                    .AppendLine();
                }
            }

            glslShaderCode.Append(glslShaderWriter.Text);

            var realShaderSource = glslShaderCode.ToString();

            // optimize shader
            var optShaderSource = RunOptimizer(realShaderSource, isOpenGLES, false, pipelineStage == PipelineStage.Vertex);

            if (!String.IsNullOrEmpty(optShaderSource))
            {
                realShaderSource = optShaderSource;
            }

            var rawData    = Encoding.ASCII.GetBytes(realShaderSource);
            var bytecodeId = ObjectId.FromBytes(rawData);
            var bytecode   = new ShaderBytecode(bytecodeId, rawData);

            bytecode.Stage = stage;

            shaderBytecodeResult.Bytecode = bytecode;
            return(shaderBytecodeResult);
        }