public static ShaderData CreatePureGLSL(byte[] byteCode, string filename, bool isVertexShader, List <ConstantBufferData> cbuffers, int sharedIndex, Dictionary <string, SamplerStateInfo> samplerStates, string shaderInfo, bool debug)
        {
            var dxshader = new ShaderData();

            dxshader.SharedIndex = sharedIndex;
            dxshader.Bytecode    = (byte[])byteCode.Clone();
            // Use MojoShader to convert the HLSL bytecode to GLSL.
            string glsl = System.Text.Encoding.ASCII.GetString(byteCode);

            if (isVertexShader)
            {
                glsl = AddPosFixup(glsl);
            }

            Dictionary <string, MojoShader.MOJOSHADER_usage> usageMapping = new Dictionary <string, MojoShader.MOJOSHADER_usage> ();
            XmlDocument doc = new XmlDocument();

            doc.LoadXml(shaderInfo);
            XmlElement shader = (XmlElement)doc.FirstChild;

            foreach (XmlElement attribute in shader.ChildNodes)
            {
                if (attribute.Name == "attribute")
                {
                    usageMapping.Add(attribute.GetAttribute("name"), (MojoShader.MOJOSHADER_usage)Enum.Parse(typeof(MojoShader.MOJOSHADER_usage), "MOJOSHADER_USAGE_" + attribute.InnerText.ToUpper(), true));
                }
            }
            Additional.GLSLShaderParser parser = new Additional.GLSLShaderParser(glsl, filename, isVertexShader, usageMapping);
            if (!parser.Parse())
            {
                return(null);
            }

            dxshader.IsVertexShader = isVertexShader;

            dxshader._attributes = parser.Attributes.ToArray();

            var symbols = parser.Symbols.ToArray();

            //try to put the symbols in the order they are eventually packed into the uniform arrays
            //this /should/ be done by pulling the info from mojoshader
            Array.Sort(symbols, delegate(MojoShader.MOJOSHADER_symbol a, MojoShader.MOJOSHADER_symbol b) {
                uint va = a.register_index;
                if (a.info.elements == 1)
                {
                    va += 1024;                     //hax. mojoshader puts array objects first
                }
                uint vb = b.register_index;
                if (b.info.elements == 1)
                {
                    vb += 1024;
                }
                return(va.CompareTo(vb));
            }
                       ); //(a, b) => ((int)(a.info.elements > 1))a.register_index.CompareTo(b.register_index));

            // NOTE: It seems the latest versions of MojoShader only
            // output vec4 register sets.  We leave the code below, but
            // the runtime has been optimized for this case.

            // For whatever reason the register indexing is
            // incorrect from MojoShader.
            {
                uint bool_index   = 0;
                uint float4_index = 0;
                uint int4_index   = 0;

                for (var i = 0; i < symbols.Length; i++)
                {
                    switch (symbols [i].register_set)
                    {
                    case MojoShader.MOJOSHADER_symbolRegisterSet.MOJOSHADER_SYMREGSET_BOOL:
                        symbols [i].register_index = bool_index;
                        bool_index += symbols [i].register_count;
                        break;

                    case MojoShader.MOJOSHADER_symbolRegisterSet.MOJOSHADER_SYMREGSET_FLOAT4:
                        symbols [i].register_index = float4_index;
                        float4_index += symbols [i].register_count;
                        break;

                    case MojoShader.MOJOSHADER_symbolRegisterSet.MOJOSHADER_SYMREGSET_INT4:
                        symbols [i].register_index = int4_index;
                        int4_index += symbols [i].register_count;
                        break;
                    }
                }
            }
            // Get the samplers.
            var samplers = parser.Samplers.ToArray();

            dxshader._samplers = new Sampler[samplers.Length];
            for (var i = 0; i < samplers.Length; i++)
            {
                // We need the original sampler name... look for that in the symbols.
                var originalSamplerName =
                    symbols.First(e => e.register_set == MojoShader.MOJOSHADER_symbolRegisterSet.MOJOSHADER_SYMREGSET_SAMPLER &&
                                  e.register_index == samplers [i].index
                                  ).name;

                var sampler = new Sampler {
                    //sampler mapping to parameter is unknown atm
                    parameter = -1,

                    // GLSL needs the MojoShader mangled sampler name.
                    samplerName = samplers [i].name,

                    // By default use the original sampler name for the parameter name.
                    parameterName = originalSamplerName,

                    textureSlot = samplers [i].index,
                    samplerSlot = samplers [i].index,
                    type        = samplers [i].type,
                };

                SamplerStateInfo state;
                if (samplerStates.TryGetValue(originalSamplerName, out state))
                {
                    sampler.state         = state.State;
                    sampler.parameterName = state.TextureName ?? originalSamplerName;
                }

                // Store the sampler.
                dxshader._samplers [i] = sampler;
            }

            // Gather all the parameters used by this shader.
            var symbol_types = new[] {
                new { name = dxshader.IsVertexShader ? "vs_uniforms_bool" : "ps_uniforms_bool", set = MojoShader.MOJOSHADER_symbolRegisterSet.MOJOSHADER_SYMREGSET_BOOL, },
                new { name = dxshader.IsVertexShader ? "vs_uniforms_ivec4" : "ps_uniforms_ivec4", set = MojoShader.MOJOSHADER_symbolRegisterSet.MOJOSHADER_SYMREGSET_INT4, },
                new { name = dxshader.IsVertexShader ? "vs_uniforms_vec4" : "ps_uniforms_vec4", set = MojoShader.MOJOSHADER_symbolRegisterSet.MOJOSHADER_SYMREGSET_FLOAT4, },
            };
            var cbuffer_index = new List <int> ();

            for (var i = 0; i < symbol_types.Length; i++)
            {
                var cbuffer = new ConstantBufferData(symbol_types [i].name,
                                                     symbol_types [i].set,
                                                     symbols);
                if (cbuffer.Size == 0)
                {
                    continue;
                }

                var match = cbuffers.FindIndex(e => e.SameAs(cbuffer));
                if (match == -1)
                {
                    cbuffer_index.Add(cbuffers.Count);
                    cbuffers.Add(cbuffer);
                }
                else
                {
                    cbuffer_index.Add(match);
                }
            }
            dxshader._cbuffers = cbuffer_index.ToArray();



            //TODO: glslCode translator


            // TODO: This sort of sucks... why does MojoShader not produce
            // code valid for GLES out of the box?

            // GLES platforms do not like this.
            //glsl = glsl.Replace ("#version 110", "");

            // Add the required precision specifiers for GLES.
            AddPrecisions(glsl, dxshader.IsVertexShader, debug);


            // Store the code for serialization.
            dxshader.ShaderCode = Encoding.ASCII.GetBytes(glsl);
            return(dxshader);
        }
Ejemplo n.º 2
0
        private d3dx_state CreateShader(ShaderInfo shaderInfo, string shaderFilename, string shaderXML, bool isVertexShader, ContentProcessorContext context)
        {
            // Compile the shader.

            byte[] bytecode;
            if (shaderInfo.Profile == ShaderProfile.DirectX_11 || shaderInfo.Profile == ShaderProfile.OpenGL)
            {
                throw new NotImplementedException("HLSL not implemented here");
            }
            else if (shaderInfo.Profile == ShaderProfile.PureGLSL)
            {
                bytecode = CompileGLSL(shaderInfo, shaderFilename, shaderXML, context);
            }
            else
            {
                throw new NotSupportedException("Unknown shader profile!");
            }

            // First look to see if we already created this same shader.
            ShaderData shaderData = null;

            foreach (var shader in Shaders)
            {
                if (bytecode.SequenceEqual(shader.Bytecode))
                {
                    shaderData = shader;
                    break;
                }
            }

            // Create a new shader.
            if (shaderData == null)
            {
                if (shaderInfo.Profile == ShaderProfile.DirectX_11)
                {
                    throw new NotImplementedException("HLSL not implemented");//shaderData = ShaderData.CreateHLSL(bytecode, isVertexShader, ConstantBuffers, Shaders.Count, shaderInfo.SamplerStates, shaderInfo.Debug);
                }
                else if (shaderInfo.Profile == ShaderProfile.PureGLSL)
                {
                    shaderData = ShaderData.CreatePureGLSL(bytecode, shaderFilename, isVertexShader, ConstantBuffers, Shaders.Count, shaderInfo.SamplerStates, shaderXML, shaderInfo.Debug);
                }
                else
                {
                    throw new NotSupportedException("Unknown shader profile!");
                }

                Shaders.Add(shaderData);
            }

            var state = new d3dx_state();

            state.index     = 0;
            state.type      = STATE_TYPE.CONSTANT;
            state.operation = isVertexShader ? (uint)146 : (uint)147;

            state.parameter          = new d3dx_parameter();
            state.parameter.name     = string.Empty;
            state.parameter.semantic = string.Empty;
            state.parameter.class_   = D3DXPARAMETER_CLASS.OBJECT;
            state.parameter.type     = isVertexShader ? D3DXPARAMETER_TYPE.VERTEXSHADER : D3DXPARAMETER_TYPE.PIXELSHADER;
            state.parameter.rows     = 0;
            state.parameter.columns  = 0;
            state.parameter.data     = shaderData.SharedIndex;

            return(state);
        }