Ejemplo n.º 1
0
        private CodeExpression GeneratePreShaderFloatDefaults(TechniqueExtraData defaults, RegisterSet registers, int count, CompileDirectives directives, out int offset)
        {
            offset = 0;
            if (count == 0 || defaults == null)
            {
                return(null);
            }

            Vector4[] constants = new Vector4[count];
            bool      set       = false;

            foreach (KeyValuePair <string, Vector4[]> entry in defaults.DefaultSingleValues)
            {
                Register reg;
                if (registers.TryGetRegister(entry.Key, out reg))
                {
                    if (reg.Category == RegisterCategory.Float4)
                    {
                        for (int i = 0; i < Math.Max(1, reg.ArraySize) && i < entry.Value.Length && i < count - reg.Index; i++)
                        {
                            constants[i + reg.Index] = entry.Value[i];
                            set = true;
                        }
                    }
                }
            }

            if (!set)
            {
                return(null);
            }
            return(InitaliseConstants(count, constants, directives, out offset));
        }
Ejemplo n.º 2
0
        private void CreateConstantSetters(IShaderDom shader, Action <CodeTypeMember, string> add, string name, CodeExpression assignmentField, CodeExpression assignmentArrayField)
        {
            /*
             * Something like:
             *
             * public void SetInvTargetSize(ref Microsoft.Xna.Framework.Vector2 value)
             * {
             *      this.vreg.SetVector2(130, ref value);
             * }
             *
             * public Microsoft.Xna.Framework.Vector2 InvTargetSize
             * {
             *      set
             *      {
             *              this.SetInvTargetSize(ref value);
             *      }
             * }*/

            Register reg;
            Type     dataType;
            bool     hasSetMethod;
            int      stride;

            if (!ExtractRegType(name, out reg, out dataType, out hasSetMethod, out stride))
            {
                return;
            }

            Type arrayOrSingleType = dataType;

            //right...

            //create the method of the given type.


            //public void SetInvTargetSize(ref Microsoft.Xna.Framework.Vector2 value)
            CodeStatementCollection methodStatements = new CodeStatementCollection();

            CodeParameterDeclarationExpression param = new CodeParameterDeclarationExpression(dataType, "value");

            if (reg.ArraySize == -1)
            {
                param.Direction = FieldDirection.Ref;
            }
            else
            {
                arrayOrSingleType = dataType.MakeArrayType();
                param.Type        = new CodeTypeReference(arrayOrSingleType);
            }

            CodeExpression valueRef = new CodeArgumentReferenceExpression(param.Name);

            //when there isn't a set method, there is just a set property
            if (!hasSetMethod)
            {
                valueRef = new CodePropertySetValueReferenceExpression();
            }

            //create the guts
            //depends on what constants use it...

            //eg:
            //this.vreg.SetVector2(130, ref value);

            Register sreg;

            if (dataType == typeof(bool))
            {
                //special case for booleans, assign the array directly.
                //looks like:
                //
                // if (preg_bool[index] != value)
                // {
                //  preg_bool[index] = value;
                //  preg_bool_changed = true;
                // }

                foreach (KeyValuePair <AsmListing, CodeExpression> listing in listingRegisters)
                {
                    RegisterSet    registers    = listing.Key.RegisterSet;
                    CodeExpression registersRef = listing.Value;

                    if (registers.TryGetRegister(name, out sreg))
                    {
                        if (listing.Key == asm.PixelShader)
                        {
                            CodeExpression arrayIndex = new CodeArrayIndexerExpression(shader.PixelShaderBooleanRegistersRef, new CodePrimitiveExpression(sreg.Index));

                            CodeStatement assign = new CodeAssignStatement(arrayIndex, new CodePropertySetValueReferenceExpression());
                            CodeStatement change = new CodeAssignStatement(shader.PixelShaderBooleanRegistersChangedRef, new CodePrimitiveExpression(true));

                            CodeStatement condition = new CodeConditionStatement(
                                new CodeBinaryOperatorExpression(arrayIndex, CodeBinaryOperatorType.IdentityInequality, new CodePropertySetValueReferenceExpression()),
                                new CodeStatement[] { assign, change });

                            methodStatements.Add(condition);
                        }
                        if (listing.Key == asm.VertexShader)
                        {
                            CodeExpression arrayIndex = new CodeArrayIndexerExpression(shader.VertexShaderBooleanRegistersRef, new CodePrimitiveExpression(sreg.Index));

                            CodeStatement assign = new CodeAssignStatement(arrayIndex, new CodePropertySetValueReferenceExpression());
                            CodeStatement change = new CodeAssignStatement(shader.VertexShaderBooleanRegistersChangedRef, new CodePrimitiveExpression(true));

                            CodeStatement condition = new CodeConditionStatement(
                                new CodeBinaryOperatorExpression(arrayIndex, CodeBinaryOperatorType.IdentityInequality, new CodePropertySetValueReferenceExpression()),
                                new CodeStatement[] { assign, change });

                            methodStatements.Add(condition);
                        }
                    }
                }
            }
            else
            {
                string targetName = "Set" + dataType.Name;

                if (dataType == typeof(Matrix))
                {
                    targetName += stride;
                    targetName += "Transpose";
                }

                if (reg.ArraySize == -1)
                {
                    //not an array..

                    foreach (KeyValuePair <AsmListing, CodeExpression> listing in listingRegisters)
                    {
                        RegisterSet    registers    = listing.Key.RegisterSet;
                        CodeExpression registersRef = listing.Value;

                        if (registers.TryGetRegister(name, out sreg))
                        {
                            //set the regiser (eg, may be vertex shader register)
                            CodeExpression methodInvoke =
                                new CodeMethodInvokeExpression(registersRef, targetName,
                                                               new CodePrimitiveExpression(sreg.Index),
                                                               new CodeDirectionExpression(FieldDirection.Ref, valueRef));

                            methodStatements.Add(shader.ETS(methodInvoke));
                        }
                    }
                }
                else
                {
                    //is an array...
                    //simply call SetArray on the array object.
                    CodeExpression methodInvoke =
                        new CodeMethodInvokeExpression(assignmentArrayField, "SetArray",
                                                       valueRef);

                    methodStatements.Add(shader.ETS(methodInvoke));
                }
            }

            string upperName = Common.ToUpper(name);

            //there is always a setable property
            CodeMemberProperty property = new CodeMemberProperty();

            property.Name       = upperName;
            property.Type       = param.Type;
            property.Attributes = MemberAttributes.Final | MemberAttributes.Public;
            property.HasSet     = reg.ArraySize == -1;
            property.HasGet     = reg.ArraySize != -1;

            //there isn't always a set method
            CodeMemberMethod method = null;

            CodeStatement assignAttribute = null;

            if (hasSetMethod || reg.ArraySize != -1)
            {
                //create the method to set the value
                string methodName = "Set" + upperName;

                method            = new CodeMemberMethod();
                method.Name       = methodName;
                method.Attributes = MemberAttributes.Final | MemberAttributes.Public;

                method.Parameters.Add(param);
                method.Statements.AddRange(methodStatements);


                //create a property that calls the Set method if not an array, get method if it is an array

                if (reg.ArraySize == -1)
                {
                    //is not an array
                    CodeExpression invokeSetter =
                        new CodeMethodInvokeExpression(
                            shader.Instance, method.Name,
                            new CodeDirectionExpression(FieldDirection.Ref, new CodePropertySetValueReferenceExpression()));

                    property.SetStatements.Add(invokeSetter);
                }
                else
                {
                    //is an array, return the array object directly.
                    property.GetStatements.Add(new CodeMethodReturnStatement(assignmentArrayField));

                    //set the type of the property to IArray<float>, etc
                    Type interfaceType = typeof(Xen.Graphics.ShaderSystem.Constants.IArray <float>).GetGenericTypeDefinition();
                    interfaceType = interfaceType.MakeGenericType(dataType);

                    property.Type = new CodeTypeReference(interfaceType);
                }



                //call the method as well for attribute assign
                CodeExpression assignSetter =
                    new CodeMethodInvokeExpression(
                        shader.Instance, method.Name,
                        new CodeDirectionExpression(param.Direction, shader.AttributeAssignValue));

                assignAttribute = shader.ETS(assignSetter);
            }
            else
            {
                //create a property to directly set the value

                property.SetStatements.AddRange(methodStatements);

                //attribute assign sets the property
                assignAttribute = new CodeAssignStatement(
                    new CodePropertyReferenceExpression(shader.Instance, property.Name),
                    shader.AttributeAssignValue);
            }


            if (reg.ArraySize > 0)
            {
                if (method != null)
                {
                    add(method, string.Format("Set the shader array value '{0} {1}[{2}]'", reg.Type, reg.Name, reg.ArraySize));
                }
                add(property, string.Format("Get the array for the shader value '{0} {1}[{2}]'", reg.Type, reg.Name, reg.ArraySize));
            }
            else
            {
                if (method != null)
                {
                    add(method, string.Format("Set the shader value '{0} {1}'", reg.Type, reg.Name));
                }
                add(property, string.Format("Assign the shader value '{0} {1}'", reg.Type, reg.Name));
            }

            //create the attribute assignment value statement.

            List <CodeStatement> assignList;

            if (!attributeAssignment.TryGetValue(arrayOrSingleType, out assignList))
            {
                assignList = new List <CodeStatement>();
                attributeAssignment.Add(arrayOrSingleType, assignList);
            }

            //create the statement...

            CodeExpression assignIdsMatch =
                new CodeBinaryOperatorExpression(shader.AttributeAssignId, CodeBinaryOperatorType.IdentityEquality, assignmentField);

            CodeConditionStatement performAssign =
                new CodeConditionStatement(assignIdsMatch,
                                           assignAttribute,                                                   //call the assignment code
                                           new CodeMethodReturnStatement(new CodePrimitiveExpression(true))); //return true, set correctly.

            assignList.Add(performAssign);
        }
Ejemplo n.º 3
0
        public override void AddConstructor(IShaderDom shader, Action <CodeStatement> add)
        {
            //set the semantic change IDs to -1
            foreach (SemanticMapping mapping in semanticMapping)
            {
                for (int i = 0; i < mapping.ChangeRefs.Length; i++)
                {
                    CodeAssignStatement assign = new CodeAssignStatement(mapping.ChangeRefs[i], new CodePrimitiveExpression(-1));

                    add(assign);
                }
            }

            //init the array attributes
            for (int i = 0; i < attributeNames.Count; i++)
            {
                //if it's an array, it needs an array object...

                Register reg;
                Type     dataType;

                if (ExtractRegType(attributeNames[i], out reg, out dataType) && reg.ArraySize != -1)
                {
                    //things get a bit funky here.
                    //if the array is used by more than one register set, it must be wrapped up in a 'DualArray'
                    //so a call to 'SetValue' on the array gets passed to both copies.
                    //This can occur if both the vertex and pixel shader access a constant array, or a preshader, etc.
                    Type dualType = typeof(Xen.Graphics.ShaderSystem.Constants.DualArray <float>).GetGenericTypeDefinition();
                    dualType = dualType.MakeGenericType(dataType);

                    //this.attributeArrayFields[i].FieldName

                    CodeExpression initExpression = null;
                    Type           arrayType      = GetArrayType(reg);

                    foreach (KeyValuePair <AsmListing, CodeExpression> listing in listingRegisters)
                    {
                        Register       sreg;
                        RegisterSet    registers    = listing.Key.RegisterSet;
                        CodeExpression registersRef = listing.Value;

                        if (registers.TryGetRegister(reg.Name, out sreg))
                        {
                            CodeExpression create;

                            create = new CodeObjectCreateExpression(arrayType,
                                                                    registersRef, //vreg
                                                                    new CodePrimitiveExpression(sreg.Index),
                                                                    new CodePrimitiveExpression(sreg.Size));

                            if (initExpression == null)
                            {
                                initExpression = create;
                            }
                            else
                            {
                                //darn. wrap in a dual array.
                                initExpression = new CodeObjectCreateExpression(
                                    dualType,
                                    create, initExpression);
                            }
                        }
                    }

                    CodeAssignStatement assign = new CodeAssignStatement(this.attributeArrayFields[i], initExpression);
                    add(assign);
                }
            }

            //set the global change IDs to -1 (unless it's an array)...
            foreach (GlobalAttribute global in globals)
            {
                int changeRefIndex = 0;
                foreach (KeyValuePair <AsmListing, CodeExpression> listing in listingRegisters)
                {
                    Register       sreg;
                    RegisterSet    registers    = listing.Key.RegisterSet;
                    CodeExpression registersRef = listing.Value;

                    if (registers.TryGetRegister(global.Register.Name, out sreg) && sreg.Category != RegisterCategory.Boolean)
                    {
                        CodeAssignStatement assign = new CodeAssignStatement(global.ChangeRefs[changeRefIndex], new CodePrimitiveExpression(-1));

                        add(assign);


                        //arrays require the array wrapper to be initalised
                        if (global.Register.ArraySize != -1)
                        {
                            //arrays are stored differently.. eg as IArray<Matrix>
                            //eg:
                            //new Xen.Graphics.ShaderSystem.Constants.Matrix4Array(this.vreg, 217, 4);

                            Type arrayType = GetArrayType(global.Register);

                            CodeExpression create;

                            create = new CodeObjectCreateExpression(arrayType,
                                                                    registersRef, //vreg
                                                                    new CodePrimitiveExpression(sreg.Index),
                                                                    new CodePrimitiveExpression(sreg.Size));

                            assign = new CodeAssignStatement(global.ArrayRefs[changeRefIndex], create);
                            add(assign);
                        }

                        changeRefIndex++;
                    }
                }
            }
        }
Ejemplo n.º 4
0
        public override void AddBind(IShaderDom shader, Action <CodeStatement, string> add)
        {
            //bind the semantics bound attributes
            foreach (SemanticMapping mapping in semanticMapping)
            {
                //eg:
                //state.SetWorldMatrix(this.vreg.Matrix4Transpose(8), ref this.v_8);

                string method    = string.Format("Set{0}{1}", mapping.Type.Mapping, mapping.Type.Type.Name);
                bool   transpose = mapping.Type.Transpose ^ (mapping.Type.Type == typeof(Matrix));

                string registerTypeName = mapping.Type.Type.Name;
                if (mapping.Type.Type == typeof(Matrix))
                {
                    registerTypeName += (int)mapping.Register.Rank;
                }
                if (transpose)
                {
                    registerTypeName += "Transpose";
                }

                //for each register set, see if it uses this mapping

                int changeRefIndex = 0;
                foreach (KeyValuePair <AsmListing, CodeExpression> listing in listingRegisters)
                {
                    Register       sreg;
                    RegisterSet    registers    = listing.Key.RegisterSet;
                    CodeExpression registersRef = listing.Value;

                    if (registers.TryGetRegister(mapping.Register.Name, out sreg))
                    {
                        //it does.. so the constants need setting..
                        //state.SetWorldMatrix(this.vreg.Matrix4Transpose(8), ref this.v_8);

                        CodeExpression changeRef = new CodeDirectionExpression(FieldDirection.Ref, mapping.ChangeRefs[changeRefIndex]);

                        CodeExpression getRegister =                            //this.vreg.Matrix4Transpose(8)
                                                     new CodeMethodInvokeExpression(registersRef, registerTypeName, new CodePrimitiveExpression(sreg.Index));

                        //invoke
                        CodeExpression invokeSet =
                            new CodeMethodInvokeExpression(shader.ShaderSystemRef, method, getRegister, changeRef);

                        add(shader.ETS(invokeSet), changeRefIndex != 0 ? null : string.Format("Set the value for attribute '{0}'", mapping.Register.Name));

                        changeRefIndex++;
                    }
                }
            }

            //bind the shader globals

            foreach (GlobalAttribute global in globals)
            {
                string registerTypeName = global.Type.Name;
                if (global.Type == typeof(Matrix))
                {
                    registerTypeName += (int)global.Register.Rank;
                    registerTypeName += "Transpose";
                }

                int changeRefIndex = 0;
                foreach (KeyValuePair <AsmListing, CodeExpression> listing in listingRegisters)
                {
                    Register       sreg;
                    RegisterSet    registers    = listing.Key.RegisterSet;
                    CodeExpression registersRef = listing.Value;

                    if (registers.TryGetRegister(global.Register.Name, out sreg))
                    {
                        //special case the booleans, as they have different logic to set globally.
                        if (sreg.Category == RegisterCategory.Boolean)
                        {
                            if (global.Register.ArraySize != -1)
                            {
                                throw new CompileException("'GLOBAL' Boolean Arrays are not supported");
                            }

                            //this is a bit of a hack :-/
                            //need to figure out if this is a vertex or pixel boolean constant.
                            if (listing.Key == asm.VertexShader)
                            {
                                add(shader.ETS(
                                        new CodeMethodInvokeExpression(shader.ShaderSystemRef, "SetGlobal", shader.VertexShaderBooleanRegistersRef, new CodePrimitiveExpression(sreg.Index), global.GlobalIdRef, new CodeDirectionExpression(FieldDirection.Ref, shader.VertexShaderBooleanRegistersChangedRef))),
                                    string.Format("Set the value for global 'bool {0}'", global.Register.Name));
                            }
                            if (listing.Key == asm.PixelShader)
                            {
                                add(shader.ETS(
                                        new CodeMethodInvokeExpression(shader.ShaderSystemRef, "SetGlobal", shader.PixelShaderBooleanRegistersRef, new CodePrimitiveExpression(sreg.Index), global.GlobalIdRef, new CodeDirectionExpression(FieldDirection.Ref, shader.PixelShaderBooleanRegistersChangedRef))),
                                    string.Format("Set the value for global 'bool {0}'", global.Register.Name));
                            }
                        }
                        else
                        {
                            //eg:
                            //state.SetGlobal(this.vreg.Matrix4Transpose(8), ShadowShaderBlend.g_id0, ref this.g_0);

                            CodeExpression getRegister =                                //this.vreg.Matrix4Transpose(8)
                                                         new CodeMethodInvokeExpression(registersRef, registerTypeName, new CodePrimitiveExpression(sreg.Index));

                            CodeExpression changeParam = new CodeDirectionExpression(FieldDirection.Ref, global.ChangeRefs[changeRefIndex]);

                            CodeExpression invokeSet;

                            //logic changes for arrays

                            if (global.Register.ArraySize != -1)
                            {
                                invokeSet =
                                    new CodeMethodInvokeExpression(shader.ShaderSystemRef, "SetGlobal", global.ArrayRefs[changeRefIndex], global.GlobalIdRef, changeParam);
                                //state.SetGlobal(this.ga0, ShadowShaderBlend.g_id0, ref this.g_0);
                            }
                            else
                            {
                                //state.SetGlobal(this.vreg.Matrix4Transpose(8), ShadowShaderBlend.g_id0, ref this.g_0);
                                invokeSet =
                                    new CodeMethodInvokeExpression(shader.ShaderSystemRef, "SetGlobal", getRegister, global.GlobalIdRef, changeParam);
                            }

                            add(shader.ETS(invokeSet), changeRefIndex != 0 ? null : string.Format("Set the value for global '{0}'", global.Register.Name));

                            changeRefIndex++;
                        }
                    }
                }
            }
        }
Ejemplo n.º 5
0
        //pull a semantic bound register
        private void ExtractSemantic(IShaderDom shader, Register reg)
        {
            string semantic = reg.Semantic;

            Type dataType = null;

            switch (reg.Rank)
            {
            case RegisterRank.FloatNx1:
            {
                switch (reg.Type)
                {
                case "float":
                case "float1":                                //?
                    dataType = typeof(Single);
                    break;

                case "float2":
                    dataType = typeof(Vector2);
                    break;

                case "float3":
                    dataType = typeof(Vector3);
                    break;

                case "float4":
                    dataType = typeof(Vector4);
                    break;
                }
            }
            break;

            case RegisterRank.FloatNx2:
            case RegisterRank.FloatNx3:
            case RegisterRank.FloatNx4:
                dataType = typeof(Matrix);
                break;

            case RegisterRank.IntNx1:
            case RegisterRank.IntNx2:
            case RegisterRank.IntNx3:
            case RegisterRank.IntNx4:
            {
                //ints are almost always mapped to floats for semantic bound types (EG vertex count)
                //since the register category has been validated to Float4, this is the case here
                switch (reg.Type)
                {
                case "int":
                case "int1":                                //?
                    dataType = typeof(Single);
                    break;

                case "int2":
                    dataType = typeof(Vector2);
                    break;

                case "int3":
                    dataType = typeof(Vector3);
                    break;

                case "int4":
                    dataType = typeof(Vector4);
                    break;
                }
            }
            break;

            case RegisterRank.Bool:
                dataType = typeof(Single);
                break;
            }

            if (reg.Category == RegisterCategory.Boolean)
            {
                dataType = typeof(bool);
            }


            if (semantic.Length == 6 && semantic.Equals("global", StringComparison.InvariantCultureIgnoreCase))
            {
                //special case global value.

                if (dataType == null)
                {
                    throw new CompileException(string.Format("Error parsing semantic for '{0}'. Global values of type '{1}' are not supported.", reg.Name, reg.Type));
                }

                GlobalAttribute global = new GlobalAttribute();
                global.Register = reg;
                global.Type     = dataType;

                global.GlobalIdRef = new CodeFieldReferenceExpression(shader.ShaderClassEx, string.Format("gid{0}", globals.Count));

                List <CodeFieldReferenceExpression> globalRefs = new List <CodeFieldReferenceExpression>();
                List <CodeFieldReferenceExpression> arrayRefs  = new List <CodeFieldReferenceExpression>();

                foreach (KeyValuePair <AsmListing, CodeExpression> listing in listingRegisters)
                {
                    Register       sreg;
                    RegisterSet    registers    = listing.Key.RegisterSet;
                    CodeExpression registersRef = listing.Value;

                    if (registers.TryGetRegister(reg.Name, out sreg))
                    {
                        if (sreg.Category != RegisterCategory.Boolean)
                        {
                            string refId = string.Format("gc{0}", globalRefCount);
                            globalRefs.Add(new CodeFieldReferenceExpression(shader.Instance, refId));

                            if (reg.ArraySize != -1)
                            {
                                refId = string.Format("ga{0}", globalRefCount);
                                arrayRefs.Add(new CodeFieldReferenceExpression(shader.Instance, refId));
                            }
                            globalRefCount++;
                        }
                    }
                }

                global.ChangeRefs = globalRefs.ToArray();
                global.ArrayRefs  = arrayRefs.ToArray();

                globals.Add(global);
                return;
            }

            if (reg.ArraySize != -1)
            {
                //INVALID. EXTERMINATE.
                throw new CompileException(string.Format("Shader attribute '{0}' is defined as an array and has a semantic '{1}'. Semantics other than 'GLOBAL' are invalid for Array types.", reg.Name, reg.Semantic));
            }

            bool isTranspose = semantic.Length > 9 && semantic.EndsWith("transpose", StringComparison.InvariantCultureIgnoreCase);

            if (isTranspose)
            {
                semantic = semantic.Substring(0, semantic.Length - 9);
            }

            SemanticType?dataSemanticType = null;

            foreach (SemanticType semanticType in semanticTypes)
            {
                if (semanticType.Transpose == isTranspose &&
                    semanticType.Type == dataType &&
                    semanticType.Mapping.Equals(semantic, StringComparison.InvariantCultureIgnoreCase))
                {
                    dataSemanticType = semanticType;
                    break;
                }
            }

            if (dataSemanticType == null)
            {
                //INVALID. EXTERMINATE.
                throw new CompileException(string.Format("Shader attribute '{0}' has unrecognised semantic '{1}'.", reg.Name, reg.Semantic));
            }

            //create the mapping...
            SemanticMapping mapping = new SemanticMapping();

            mapping.Register = reg;
            mapping.Type     = dataSemanticType.Value;

            //figure out how often this semantic is used..
            List <CodeFieldReferenceExpression> changeRefs = new List <CodeFieldReferenceExpression>();

            foreach (KeyValuePair <AsmListing, CodeExpression> listing in listingRegisters)
            {
                Register       sreg;
                RegisterSet    registers    = listing.Key.RegisterSet;
                CodeExpression registersRef = listing.Value;

                if (registers.TryGetRegister(reg.Name, out sreg))
                {
                    string changeId = string.Format("sc{0}", semanticMappingRefCount++);
                    changeRefs.Add(new CodeFieldReferenceExpression(shader.Instance, changeId));
                }
            }

            mapping.ChangeRefs = changeRefs.ToArray();

            this.semanticMapping.Add(mapping);
        }