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 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);
        }
Exemplo n.º 2
0
        private string Compile(string shaderSource, string entryPoint, ShaderStage stage, bool isOpenGLES, bool isOpenGLES3, ShaderBytecodeResult shaderBytecodeResult, string sourceFilename = null)
        {
            if (isOpenGLES && !isOpenGLES3 && renderTargetCount > 1)
            {
                shaderBytecodeResult.Error("OpenGL ES 2 does not support multiple render targets.");
            }

            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(null);
            }

            string shaderString          = null;
            var    generateUniformBlocks = isOpenGLES && isOpenGLES3;

            // null entry point for pixel shader means no pixel shader. In that case, we return a default function.
            if (entryPoint == null && stage == ShaderStage.Pixel && isOpenGLES)
            {
                shaderString = "out float fragmentdepth; void main(){ fragmentdepth = gl_FragCoord.z; }";
            }
            else
            {
                // 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, isOpenGLES3);
                var glslShader    = glslConvertor.Convert(shaderSource, entryPoint, pipelineStage, sourceFilename, shaderBytecodeResult);

                if (glslShader == null || shaderBytecodeResult.HasErrors)
                {
                    return(null);
                }

                // Add std140 layout
                foreach (var constantBuffer in glslShader.Declarations.OfType <ConstantBuffer>())
                {
                    if (isOpenGLES3) // TODO: for OpenGL too?
                    {
                        var layoutQualifier = constantBuffer.Qualifiers.OfType <SiliconStudio.Shaders.Ast.Glsl.LayoutQualifier>().FirstOrDefault();
                        if (layoutQualifier == null)
                        {
                            layoutQualifier            = new SiliconStudio.Shaders.Ast.Glsl.LayoutQualifier();
                            constantBuffer.Qualifiers |= layoutQualifier;
                        }
                        layoutQualifier.Layouts.Add(new LayoutKeyValue("std140"));
                    }
                    else
                    {
                        constantBuffer.Qualifiers |= new LayoutQualifier(new LayoutKeyValue("std140"));
                    }
                }

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

                if (isOpenGLES)
                {
                    glslShaderWriter.TrimFloatSuffix = true;

                    glslShaderWriter.GenerateUniformBlocks = generateUniformBlocks;

                    if (!isOpenGLES3)
                    {
                        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);

                shaderString = glslShaderWriter.Text;
            }

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

            // Append some header depending on target
            if (isOpenGLES)
            {
                if (isOpenGLES3)
                {
                    glslShaderCode
                    .AppendLine("#version 300 es")     // TODO: 310 version?
                    .AppendLine();
                }

                if (pipelineStage == PipelineStage.Pixel)
                {
                    glslShaderCode
                    .AppendLine("precision highp float;")
                    .AppendLine();
                }
            }
            else
            {
                glslShaderCode
                .AppendLine("#version 420")
                .AppendLine();
            }

            if ((!isOpenGLES || isOpenGLES3) && pipelineStage == PipelineStage.Pixel && renderTargetCount > 0)
            {
                // TODO: identifiers starting with "gl_" should be reserved. Compilers usually accept them but it may should be prevented.
                glslShaderCode
                .AppendLine("#define gl_FragData _glesFragData")
                .AppendLine("out vec4 gl_FragData[" + renderTargetCount + "];")
                .AppendLine();
            }

            glslShaderCode.Append(shaderString);

            var realShaderSource = glslShaderCode.ToString();

#if SILICONSTUDIO_PLATFORM_WINDOWS_DESKTOP
            // optimize shader
            try
            {
                var optShaderSource = RunOptimizer(shaderBytecodeResult, realShaderSource, isOpenGLES, isOpenGLES3, pipelineStage == PipelineStage.Vertex);
                if (!String.IsNullOrEmpty(optShaderSource))
                {
                    realShaderSource = optShaderSource;
                }
            }
            catch (Exception e)
            {
                shaderBytecodeResult.Warning("Could not run GLSL optimizer:\n{0}", e.Message);
            }
#else
            shaderBytecodeResult.Warning("GLSL optimized has not been executed because it is currently not supported on this platform.");
#endif

            return(realShaderSource);
        }
Exemplo n.º 3
0
        private string Compile(string shaderSource, string entryPoint, ShaderStage stage, bool isOpenGLES, bool isOpenGLES3, ShaderBytecodeResult shaderBytecodeResult, string sourceFilename = null)
        {
            if (isOpenGLES && !isOpenGLES3 && renderTargetCount > 1)
                shaderBytecodeResult.Error("OpenGL ES 2 does not support multiple render targets.");

            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 null;

            string shaderString = null;
            var generateUniformBlocks = isOpenGLES && isOpenGLES3;

            // null entry point for pixel shader means no pixel shader. In that case, we return a default function.
            if (entryPoint == null && stage == ShaderStage.Pixel && isOpenGLES)
            {
                shaderString = "void main(){}";
            }
            else
            {
                // 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, isOpenGLES3);
                var glslShader = glslConvertor.Convert(shaderSource, entryPoint, pipelineStage, sourceFilename, shaderBytecodeResult);

                if (glslShader == null || shaderBytecodeResult.HasErrors)
                    return null;

                // Add std140 layout
                foreach (var constantBuffer in glslShader.Declarations.OfType<ConstantBuffer>())
                {
                    if (isOpenGLES3) // TODO: for OpenGL too?
                    {
                        var layoutQualifier = constantBuffer.Qualifiers.OfType<SiliconStudio.Shaders.Ast.Glsl.LayoutQualifier>().FirstOrDefault();
                        if (layoutQualifier == null)
                        {
                            layoutQualifier = new SiliconStudio.Shaders.Ast.Glsl.LayoutQualifier();
                            constantBuffer.Qualifiers |= layoutQualifier;
                        }
                        layoutQualifier.Layouts.Add(new LayoutKeyValue("std140"));
                    }
                    else
                    {
                        constantBuffer.Qualifiers |= new LayoutQualifier(new LayoutKeyValue("std140"));
                    }
                }

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

                if (isOpenGLES)
                {
                    glslShaderWriter.TrimFloatSuffix = true;

                    glslShaderWriter.GenerateUniformBlocks = generateUniformBlocks;

                    if (!isOpenGLES3)
                    {
                        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);

                shaderString = glslShaderWriter.Text;
            }

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

            // Append some header depending on target
            if (isOpenGLES)
            {
                if (isOpenGLES3)
                    glslShaderCode
                        .AppendLine("#version 300 es") // TODO: 310 version?
                        .AppendLine();

                if (generateUniformBlocks) // TODO: is it really needed? It produces only a warning.
                    glslShaderCode
                        .AppendLine("#extension GL_EXT_gpu_shader4 : enable")
                        .AppendLine("#extension GL_ARB_gpu_shader5 : enable")
                        .AppendLine();

                if (pipelineStage == PipelineStage.Pixel)
                    glslShaderCode
                        .AppendLine("precision highp float;")
                        .AppendLine();
            }
            else
            {
                glslShaderCode
                    .AppendLine("#version 420")
                    .AppendLine();
            }

            if ((!isOpenGLES || isOpenGLES3) && pipelineStage == PipelineStage.Pixel && renderTargetCount > 0)
            {
                // TODO: identifiers starting with "gl_" should be reserved. Compilers usually accept them but it may should be prevented.
                glslShaderCode
                    .AppendLine("#define gl_FragData _glesFragData")
                    .AppendLine("out vec4 gl_FragData[" + renderTargetCount + "];")
                    .AppendLine();
            }

            glslShaderCode.Append(shaderString);

            var realShaderSource = glslShaderCode.ToString();

#if SILICONSTUDIO_PLATFORM_WINDOWS_DESKTOP
            // optimize shader
            try
            {
                var optShaderSource = RunOptimizer(shaderBytecodeResult, realShaderSource, isOpenGLES, isOpenGLES3, pipelineStage == PipelineStage.Vertex);
                if (!String.IsNullOrEmpty(optShaderSource))
                    realShaderSource = optShaderSource;
            }
            catch (Exception e)
            {
                shaderBytecodeResult.Warning("Could not run GLSL optimizer:\n{0}", e.Message);
            }
#else
            shaderBytecodeResult.Warning("GLSL optimized has not been executed because it is currently not supported on this platform.");
#endif

            return realShaderSource;
        }