예제 #1
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);
        }
예제 #2
0
        private string Compile(string shaderSource, string entryPoint, ShaderStage stage, GlslShaderPlatform shaderPlatform, int shaderVersion, ShaderBytecodeResult shaderBytecodeResult, EffectReflection reflection, string sourceFilename = null)
        {
            if (shaderPlatform == GlslShaderPlatform.OpenGLES && shaderVersion < 300 && 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);
            }

            Shader glslShader;

            // null entry point means no shader. In that case, we return a default function in HlslToGlslWriter
            // TODO: support that directly in HlslToGlslConvertor?
            if (entryPoint == null)
            {
                glslShader = null;
            }
            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(shaderPlatform, shaderVersion);
                glslShader = glslConvertor.Convert(shaderSource, entryPoint, pipelineStage, sourceFilename, shaderBytecodeResult);

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

                foreach (var constantBuffer in glslShader.Declarations.OfType <ConstantBuffer>())
                {
                    // Update constant buffer itself (first time only)
                    var reflectionConstantBuffer = reflection.ConstantBuffers.FirstOrDefault(x => x.Name == constantBuffer.Name && x.Size == 0);
                    if (reflectionConstantBuffer != null)
                    {
                        // Used to compute constant buffer size and member offsets (std140 rule)
                        int constantBufferOffset = 0;

                        // Fill members
                        for (int index = 0; index < reflectionConstantBuffer.Members.Length; index++)
                        {
                            var member = reflectionConstantBuffer.Members[index];

                            // Properly compute size and offset according to std140 rules
                            var memberSize = ComputeMemberSize(ref member.Type, ref constantBufferOffset);

                            // Store size/offset info
                            member.Offset = constantBufferOffset;
                            member.Size   = memberSize;

                            // Adjust offset for next item
                            constantBufferOffset += memberSize;

                            reflectionConstantBuffer.Members[index] = member;
                        }

                        reflectionConstantBuffer.Size = constantBufferOffset;
                    }

                    // Find binding
                    var resourceBindingIndex = reflection.ResourceBindings.IndexOf(x => x.RawName == constantBuffer.Name);
                    if (resourceBindingIndex != -1)
                    {
                        MarkResourceBindingAsUsed(reflection, resourceBindingIndex, stage);
                    }
                }

                foreach (var variable in glslShader.Declarations.OfType <Variable>().Where(x => (x.Qualifiers.Contains(StorageQualifier.Uniform))))
                {
                    // Check if we have a variable that starts or ends with this name (in case of samplers)
                    // TODO: Have real AST support for all the list in Keywords.glsl
                    if (variable.Type.Name.Text.Contains("sampler1D") ||
                        variable.Type.Name.Text.Contains("sampler2D") ||
                        variable.Type.Name.Text.Contains("sampler3D") ||
                        variable.Type.Name.Text.Contains("samplerCube"))
                    {
                        // TODO: Make more robust
                        var textureBindingIndex = reflection.ResourceBindings.IndexOf(x => variable.Name.ToString().StartsWith(x.RawName));
                        var samplerBindingIndex = reflection.ResourceBindings.IndexOf(x => variable.Name.ToString().EndsWith(x.RawName));

                        if (textureBindingIndex != -1)
                        {
                            MarkResourceBindingAsUsed(reflection, textureBindingIndex, stage);
                        }

                        if (samplerBindingIndex != -1)
                        {
                            MarkResourceBindingAsUsed(reflection, samplerBindingIndex, stage);
                        }
                    }
                    else
                    {
                        var resourceBindingIndex = reflection.ResourceBindings.IndexOf(x => x.RawName == variable.Name);
                        if (resourceBindingIndex != -1)
                        {
                            MarkResourceBindingAsUsed(reflection, resourceBindingIndex, stage);
                        }
                    }
                }
            }

            // Output the result
            var glslShaderWriter = new HlslToGlslWriter(shaderPlatform, shaderVersion, pipelineStage);

            if (shaderPlatform == GlslShaderPlatform.OpenGLES && shaderVersion < 320)
            {
                glslShaderWriter.ExtraHeaders = "#define texelFetchBufferPlaceholder";
            }

            // Write shader
            glslShaderWriter.Visit(glslShader);

            var 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()
            //        .AppendLine("#define samplerBuffer sampler2D")
            //        .AppendLine("#define isamplerBuffer isampler2D")
            //        .AppendLine("#define usamplerBuffer usampler2D")
            //        .AppendLine("#define texelFetchBuffer(sampler, P) texelFetch(sampler, ivec2((P) & 0xFFF, (P) >> 12), 0)");
            //        //.AppendLine("#define texelFetchBuffer(sampler, P) texelFetch(sampler, P)");
            //}

            glslShaderCode.Append(shaderString);

            var realShaderSource = glslShaderCode.ToString();

#if SILICONSTUDIO_PLATFORM_WINDOWS_DESKTOP
            // optimize shader
            try
            {
                var optShaderSource = RunOptimizer(shaderBytecodeResult, realShaderSource, shaderPlatform, shaderVersion, 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);
        }
예제 #3
0
        private string Compile(string shaderSource, string entryPoint, ShaderStage stage, bool isOpenGLES, bool isOpenGLES3, ShaderBytecodeResult shaderBytecodeResult, EffectReflection reflection, 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"));
                    }
                }

                foreach (var constantBuffer in glslShader.Declarations.OfType <ConstantBuffer>())
                {
                    // Update constant buffer itself (first time only)
                    var reflectionConstantBuffer = reflection.ConstantBuffers.FirstOrDefault(x => x.Name == constantBuffer.Name && x.Size == 0);
                    if (reflectionConstantBuffer != null)
                    {
                        // Used to compute constant buffer size and member offsets (std140 rule)
                        int constantBufferOffset = 0;

                        // Fill members
                        for (int index = 0; index < reflectionConstantBuffer.Members.Length; index++)
                        {
                            var member = reflectionConstantBuffer.Members[index];

                            // Properly compute size and offset according to std140 rules
                            var memberSize = ComputeMemberSize(ref member, ref constantBufferOffset);

                            member.Offset = constantBufferOffset;
                            member.Size   = memberSize;

                            // Adjust offset for next item
                            constantBufferOffset += memberSize;

                            reflectionConstantBuffer.Members[index] = member;
                        }

                        reflectionConstantBuffer.Size  = constantBufferOffset;
                        reflectionConstantBuffer.Stage = stage; // Should we store a flag/bitfield?
                    }

                    // Find binding
                    var resourceBindingIndex = reflection.ResourceBindings.IndexOf(x => x.Param.RawName == constantBuffer.Name);
                    if (resourceBindingIndex != -1)
                    {
                        MarkResourceBindingAsUsed(reflection, resourceBindingIndex, stage);
                    }
                }

                foreach (var variable in glslShader.Declarations.OfType <Variable>().Where(x => (x.Qualifiers.Contains(StorageQualifier.Uniform))))
                {
                    // Check if we have a variable that starts or ends with this name (in case of samplers)
                    // TODO: Have real AST support for all the list in Keywords.glsl
                    if (variable.Type.Name.Text.Contains("sampler1D") ||
                        variable.Type.Name.Text.Contains("sampler2D") ||
                        variable.Type.Name.Text.Contains("sampler3D") ||
                        variable.Type.Name.Text.Contains("samplerCube"))
                    {
                        // TODO: Make more robust
                        var textureBindingIndex = reflection.ResourceBindings.IndexOf(x => variable.Name.ToString().StartsWith(x.Param.RawName));
                        var samplerBindingIndex = reflection.ResourceBindings.IndexOf(x => variable.Name.ToString().EndsWith(x.Param.RawName));

                        if (textureBindingIndex != -1)
                        {
                            MarkResourceBindingAsUsed(reflection, textureBindingIndex, stage);
                        }

                        if (samplerBindingIndex != -1)
                        {
                            MarkResourceBindingAsUsed(reflection, samplerBindingIndex, stage);
                        }
                    }
                    else
                    {
                        var resourceBindingIndex = reflection.ResourceBindings.IndexOf(x => x.Param.RawName == variable.Name);
                        if (resourceBindingIndex != -1)
                        {
                            MarkResourceBindingAsUsed(reflection, resourceBindingIndex, stage);
                        }
                    }
                }

                // 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);
        }
예제 #4
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;
        }
예제 #5
0
        private string Compile(string shaderSource, string entryPoint, ShaderStage stage, GlslShaderPlatform shaderPlatform, int shaderVersion, ShaderBytecodeResult shaderBytecodeResult, EffectReflection reflection, IDictionary <int, string> inputAttributeNames, Dictionary <string, int> resourceBindings, string sourceFilename = null)
        {
            if (shaderPlatform == GlslShaderPlatform.OpenGLES && shaderVersion < 300 && 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);
            }

            Shader glslShader;

            // null entry point means no shader. In that case, we return a default function in HlslToGlslWriter
            // TODO: support that directly in HlslToGlslConvertor?
            if (entryPoint == null)
            {
                glslShader = null;
            }
            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(shaderPlatform, shaderVersion);
                glslShader = glslConvertor.Convert(shaderSource, entryPoint, pipelineStage, sourceFilename, inputAttributeNames, shaderBytecodeResult);

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

                foreach (var constantBuffer in glslShader.Declarations.OfType <ConstantBuffer>())
                {
                    // Update constant buffer itself (first time only)
                    var reflectionConstantBuffer = reflection.ConstantBuffers.FirstOrDefault(x => x.Name == constantBuffer.Name && x.Size == 0);
                    if (reflectionConstantBuffer != null)
                    {
                        // Used to compute constant buffer size and member offsets (std140 rule)
                        int constantBufferOffset = 0;

                        // Fill members
                        for (int index = 0; index < reflectionConstantBuffer.Members.Length; index++)
                        {
                            var member = reflectionConstantBuffer.Members[index];

                            // Properly compute size and offset according to std140 rules
                            var memberSize = ComputeMemberSize(ref member.Type, ref constantBufferOffset);

                            // Store size/offset info
                            member.Offset = constantBufferOffset;
                            member.Size   = memberSize;

                            // Adjust offset for next item
                            constantBufferOffset += memberSize;

                            reflectionConstantBuffer.Members[index] = member;
                        }

                        reflectionConstantBuffer.Size = constantBufferOffset;
                    }

                    // Find binding
                    var resourceBindingIndex = reflection.ResourceBindings.IndexOf(x => x.RawName == constantBuffer.Name);
                    if (resourceBindingIndex != -1)
                    {
                        MarkResourceBindingAsUsed(reflection, resourceBindingIndex, stage);
                    }
                }

                foreach (var variable in glslShader.Declarations.OfType <Variable>().Where(x => (x.Qualifiers.Contains(StorageQualifier.Uniform))))
                {
                    // Check if we have a variable that starts or ends with this name (in case of samplers)
                    // TODO: Have real AST support for all the list in Keywords.glsl
                    if (variable.Type.Name.Text.Contains("sampler1D") ||
                        variable.Type.Name.Text.Contains("sampler2D") ||
                        variable.Type.Name.Text.Contains("sampler3D") ||
                        variable.Type.Name.Text.Contains("samplerCube") ||
                        variable.Type.Name.Text.Contains("samplerBuffer"))
                    {
                        // TODO: Make more robust
                        var textureBindingIndex = reflection.ResourceBindings.IndexOf(x => variable.Name.ToString().StartsWith(x.RawName));
                        var samplerBindingIndex = reflection.ResourceBindings.IndexOf(x => variable.Name.ToString().EndsWith(x.RawName));

                        if (textureBindingIndex != -1)
                        {
                            MarkResourceBindingAsUsed(reflection, textureBindingIndex, stage);
                        }

                        if (samplerBindingIndex != -1)
                        {
                            MarkResourceBindingAsUsed(reflection, samplerBindingIndex, stage);
                        }
                    }
                    else
                    {
                        var resourceBindingIndex = reflection.ResourceBindings.IndexOf(x => x.RawName == variable.Name);
                        if (resourceBindingIndex != -1)
                        {
                            MarkResourceBindingAsUsed(reflection, resourceBindingIndex, stage);
                        }
                    }
                }

                if (shaderPlatform == GlslShaderPlatform.Vulkan)
                {
                    // Defines the ordering of resource groups in Vulkan. This is mirrored in the PipelineState
                    var resourceGroups = reflection.ResourceBindings.Select(x => x.ResourceGroup ?? "Globals").Distinct().ToList();

                    var bindings = resourceGroups.SelectMany(resourceGroup => reflection.ResourceBindings
                                                             .Where(x => x.ResourceGroup == resourceGroup || (x.ResourceGroup == null && resourceGroup == "Globals"))
                                                             .GroupBy(x => new { KeyName = x.KeyInfo.KeyName, RawName = x.RawName, Class = x.Class, Type = x.Type, SlotCount = x.SlotCount, LogicalGroup = x.LogicalGroup })
                                                             .OrderBy(x => x.Key.Class == EffectParameterClass.ConstantBuffer ? 0 : 1))
                                   .ToList();

                    // Add layout(set, bindings) qualifier to all constant buffers
                    foreach (var constantBuffer in glslShader.Declarations.OfType <ConstantBuffer>())
                    {
                        var layoutBindingIndex = bindings.IndexOf(x => x.Key.RawName == constantBuffer.Name);
                        if (layoutBindingIndex != -1)
                        {
                            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("set", resourceGroups.IndexOf(resourceGroup)));
                            layoutQualifier.Layouts.Add(new LayoutKeyValue("set", 0));
                            layoutQualifier.Layouts.Add(new LayoutKeyValue("binding", layoutBindingIndex + 1));

                            resourceBindings.Add(bindings[layoutBindingIndex].Key.KeyName, layoutBindingIndex + 1);
                        }
                    }

                    // Add layout(set, bindings) qualifier to all other uniforms
                    foreach (var variable in glslShader.Declarations.OfType <Variable>().Where(x => (x.Qualifiers.Contains(StorageQualifier.Uniform))))
                    {
                        var layoutBindingIndex = bindings.IndexOf(x => variable.Name.Text.StartsWith(x.Key.RawName));

                        if (layoutBindingIndex != -1)
                        {
                            var layoutQualifier = variable.Qualifiers.OfType <SiliconStudio.Shaders.Ast.Glsl.LayoutQualifier>().FirstOrDefault();
                            if (layoutQualifier == null)
                            {
                                layoutQualifier      = new SiliconStudio.Shaders.Ast.Glsl.LayoutQualifier();
                                variable.Qualifiers |= layoutQualifier;
                            }

                            //layoutQualifier.Layouts.Add(new LayoutKeyValue("set", resourceGroups.IndexOf(resourceGroup)));
                            layoutQualifier.Layouts.Add(new LayoutKeyValue("set", 0));
                            layoutQualifier.Layouts.Add(new LayoutKeyValue("binding", layoutBindingIndex + 1));

                            resourceBindings.Add(bindings[layoutBindingIndex].Key.KeyName, layoutBindingIndex + 1);
                        }
                    }
                }
            }

            // Output the result
            var glslShaderWriter = new HlslToGlslWriter(shaderPlatform, shaderVersion, pipelineStage);

            if (shaderPlatform == GlslShaderPlatform.OpenGLES && shaderVersion < 320)
            {
                glslShaderWriter.ExtraHeaders = "#define texelFetchBufferPlaceholder";
            }

            // Write shader
            glslShaderWriter.Visit(glslShader);

            var 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()
            //        .AppendLine("#define samplerBuffer sampler2D")
            //        .AppendLine("#define isamplerBuffer isampler2D")
            //        .AppendLine("#define usamplerBuffer usampler2D")
            //        .AppendLine("#define texelFetchBuffer(sampler, P) texelFetch(sampler, ivec2((P) & 0xFFF, (P) >> 12), 0)");
            //        //.AppendLine("#define texelFetchBuffer(sampler, P) texelFetch(sampler, P)");
            //}

            glslShaderCode.Append(shaderString);

            var realShaderSource = glslShaderCode.ToString();

// TODO: Disabled because glsl optimizer don't properly put lowp/highp qualifier inside struct (which make shader compilation fails since we use struct for lighting)
//#if SILICONSTUDIO_PLATFORM_WINDOWS_DESKTOP
//            // optimize shader
//            try
//            {
//                var optShaderSource = RunOptimizer(shaderBytecodeResult, realShaderSource, shaderPlatform, shaderVersion, 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);
        }
예제 #6
0
        private string Compile(string shaderSource, string entryPoint, ShaderStage stage, GlslShaderPlatform shaderPlatform, int shaderVersion, ShaderBytecodeResult shaderBytecodeResult, EffectReflection reflection, string sourceFilename = null)
        {
            if (shaderPlatform == GlslShaderPlatform.OpenGLES && shaderVersion < 300 && 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;

            Shader glslShader;

            // null entry point means no shader. In that case, we return a default function in HlslToGlslWriter
            // TODO: support that directly in HlslToGlslConvertor?
            if (entryPoint == null)
            {
                glslShader = null;
            }
            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(shaderPlatform, shaderVersion);
                glslShader = glslConvertor.Convert(shaderSource, entryPoint, pipelineStage, sourceFilename, shaderBytecodeResult);

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

                foreach (var constantBuffer in glslShader.Declarations.OfType<ConstantBuffer>())
                {
                    // Update constant buffer itself (first time only)
                    var reflectionConstantBuffer = reflection.ConstantBuffers.FirstOrDefault(x => x.Name == constantBuffer.Name && x.Size == 0);
                    if (reflectionConstantBuffer != null)
                    {
                        // Used to compute constant buffer size and member offsets (std140 rule)
                        int constantBufferOffset = 0;

                        // Fill members
                        for (int index = 0; index < reflectionConstantBuffer.Members.Length; index++)
                        {
                            var member = reflectionConstantBuffer.Members[index];

                            // Properly compute size and offset according to std140 rules
                            var memberSize = ComputeMemberSize(ref member.Type, ref constantBufferOffset);

                            // Store size/offset info
                            member.Offset = constantBufferOffset;
                            member.Size = memberSize;

                            // Adjust offset for next item
                            constantBufferOffset += memberSize;

                            reflectionConstantBuffer.Members[index] = member;
                        }

                        reflectionConstantBuffer.Size = constantBufferOffset;
                    }

                    // Find binding
                    var resourceBindingIndex = reflection.ResourceBindings.IndexOf(x => x.RawName == constantBuffer.Name);
                    if (resourceBindingIndex != -1)
                        MarkResourceBindingAsUsed(reflection, resourceBindingIndex, stage);
                }

                foreach (var variable in glslShader.Declarations.OfType<Variable>().Where(x => (x.Qualifiers.Contains(StorageQualifier.Uniform))))
                {
                    // Check if we have a variable that starts or ends with this name (in case of samplers)
                    // TODO: Have real AST support for all the list in Keywords.glsl
                    if (variable.Type.Name.Text.Contains("sampler1D")
                        || variable.Type.Name.Text.Contains("sampler2D")
                        || variable.Type.Name.Text.Contains("sampler3D")
                        || variable.Type.Name.Text.Contains("samplerCube"))
                    {
                        // TODO: Make more robust
                        var textureBindingIndex = reflection.ResourceBindings.IndexOf(x => variable.Name.ToString().StartsWith(x.RawName));
                        var samplerBindingIndex = reflection.ResourceBindings.IndexOf(x => variable.Name.ToString().EndsWith(x.RawName));

                        if (textureBindingIndex != -1)
                            MarkResourceBindingAsUsed(reflection, textureBindingIndex, stage);

                        if (samplerBindingIndex != -1)
                            MarkResourceBindingAsUsed(reflection, samplerBindingIndex, stage);
                    }
                    else
                    {
                        var resourceBindingIndex = reflection.ResourceBindings.IndexOf(x => x.RawName == variable.Name);
                        if (resourceBindingIndex != -1)
                            MarkResourceBindingAsUsed(reflection, resourceBindingIndex, stage);
                    }
                }

            }

            // Output the result
            var glslShaderWriter = new HlslToGlslWriter(shaderPlatform, shaderVersion, pipelineStage);

            if (shaderPlatform == GlslShaderPlatform.OpenGLES && shaderVersion < 320)
            {
                glslShaderWriter.ExtraHeaders = "#define texelFetchBufferPlaceholder";
            }

            // Write shader
            glslShaderWriter.Visit(glslShader);

            var 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()
            //        .AppendLine("#define samplerBuffer sampler2D")
            //        .AppendLine("#define isamplerBuffer isampler2D")
            //        .AppendLine("#define usamplerBuffer usampler2D")
            //        .AppendLine("#define texelFetchBuffer(sampler, P) texelFetch(sampler, ivec2((P) & 0xFFF, (P) >> 12), 0)");
            //        //.AppendLine("#define texelFetchBuffer(sampler, P) texelFetch(sampler, P)");
            //}

            glslShaderCode.Append(shaderString);

            var realShaderSource = glslShaderCode.ToString();

#if SILICONSTUDIO_PLATFORM_WINDOWS_DESKTOP
            // optimize shader
            try
            {
                var optShaderSource = RunOptimizer(shaderBytecodeResult, realShaderSource, shaderPlatform, shaderVersion, 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;
        }