Esempio n. 1
0
        private static void UpdateConstantBufferHashes(EffectReflection reflection)
        {
            // Update Constant buffers description
            foreach (var constantBuffer in reflection.ConstantBuffers)
            {
                // We will generate a unique hash that depends on cbuffer layout (to easily detect if they differ when binding a new effect)
                // TODO: currently done at runtime, but it should better be done at compile time
                var hashBuilder = new ObjectIdBuilder();
                hashBuilder.Write(constantBuffer.Name);
                hashBuilder.Write(constantBuffer.Size);

                for (int i = 0; i < constantBuffer.Members.Length; ++i)
                {
                    var member = constantBuffer.Members[i];
                    constantBuffer.Members[i] = member;

                    hashBuilder.Write(member.Param.Key.Name);
                    hashBuilder.Write(member.SourceOffset);
                    hashBuilder.Write(member.SourceOffset);
                    hashBuilder.Write(member.Offset);
                    hashBuilder.Write(member.Count);
                    hashBuilder.Write(member.Size);
                    hashBuilder.Write(member.RowCount);
                    hashBuilder.Write(member.ColumnCount);
                }

                // Update the hash
                constantBuffer.Hash = hashBuilder.ComputeHash();
            }
        }
Esempio n. 2
0
        internal static void HashConstantBufferMember(ref ObjectIdBuilder hashBuilder, ref EffectValueDescription member, int baseOffset = 0)
        {
            hashBuilder.Write(member.KeyInfo.Key.Name);
            hashBuilder.Write(member.Offset - baseOffset);
            hashBuilder.Write(member.Size);

            HashType(ref hashBuilder, ref member.Type);
        }
Esempio n. 3
0
 private ShaderMixinObjectId()
 {
     objectIdBuilder = new ObjectIdBuilder();
     buffer          = Marshal.AllocHGlobal(65536);
     memStream       = new NativeMemoryStream(buffer, 65536);
     writer          = new HashSerializationWriter(memStream);
     writer.Context.SerializerSelector = new SerializerSelector("Default", "Hash");
 }
Esempio n. 4
0
 private ShaderMixinObjectId()
 {
     objectIdBuilder = new ObjectIdBuilder();
     buffer = Marshal.AllocHGlobal(65536);
     memStream = new NativeMemoryStream(buffer, 65536);
     writer = new HashSerializationWriter(memStream);
     writer.Context.SerializerSelector = new SerializerSelector("Default", "Hash");
 }
Esempio n. 5
0
        private ShaderMixinObjectId()
        {
            objectIdBuilder = new ObjectIdBuilder();
            buffer = Marshal.AllocHGlobal(65536);
            memStream = new NativeMemoryStream(buffer, 65536);
            writer = new HashSerializationWriter(memStream);
            writer.Context.SerializerSelector = new SerializerSelector();
            writer.Context.SerializerSelector.RegisterProfile("Default");
            writer.Context.SerializerSelector.RegisterSerializer(new ParameterKeyHashSerializer());
            writer.Context.SerializerSelector.RegisterSerializer(new ParameterCollectionHashSerializer());

            if (parameters == null)
                parameters = new ParameterCollection();
        }
Esempio n. 6
0
        //public abstract ParameterKey AppendKeyOverride(object obj);

        private unsafe void UpdateName()
        {
            fixed(char *bufferStart = Name)
            {
                var objectIdBuilder = new ObjectIdBuilder();

                objectIdBuilder.Write((byte *)bufferStart, sizeof(char) * Name.Length);

                var objId     = objectIdBuilder.ComputeHash();
                var objIdData = (ulong *)&objId;

                HashCode = objIdData[0] ^ objIdData[1];
            }
        }
Esempio n. 7
0
        private ShaderMixinObjectId()
        {
            objectIdBuilder = new ObjectIdBuilder();
            buffer          = Marshal.AllocHGlobal(65536);
            memStream       = new NativeMemoryStream(buffer, 65536);
            writer          = new HashSerializationWriter(memStream);
            writer.Context.SerializerSelector = new SerializerSelector();
            writer.Context.SerializerSelector.RegisterProfile("Default");
            writer.Context.SerializerSelector.RegisterSerializer(new ParameterKeyHashSerializer());
            writer.Context.SerializerSelector.RegisterSerializer(new ParameterCollectionHashSerializer());

            if (parameters == null)
            {
                parameters = new ParameterCollection();
            }
        }
Esempio n. 8
0
        public void TestSimple()
        {
            var builder = new ObjectIdBuilder();
            var buffer = ASCIIEncoding.ASCII.GetBytes("0123456789ABCDEF"); // 16 bytes
            builder.Write(buffer, 0, buffer.Length);
            var id1 = builder.ComputeHash();

            // The ObjectIdSimpleBuilder must be identical to the ObjectIdBuilder when data length is module of 16 bytes
            var simpleBuilder = new ObjectIdSimpleBuilder();
            simpleBuilder.Write(BitConverter.ToInt32(ASCIIEncoding.ASCII.GetBytes("0123"), 0));
            simpleBuilder.Write(BitConverter.ToInt32(ASCIIEncoding.ASCII.GetBytes("4567"), 0));
            simpleBuilder.Write(BitConverter.ToInt32(ASCIIEncoding.ASCII.GetBytes("89AB"), 0));
            simpleBuilder.Write(BitConverter.ToInt32(ASCIIEncoding.ASCII.GetBytes("CDEF"), 0));
            var id2 = simpleBuilder.ComputeHash();
            Assert.AreEqual(id1, id2);
        }
Esempio n. 9
0
        public void TestFull()
        {
            var builder = new ObjectIdBuilder();
            var buffer = ASCIIEncoding.ASCII.GetBytes("test");
            builder.Write(buffer, 0, buffer.Length);
            var id1 = builder.ComputeHash();
            var id1_verified = new ObjectId(StringToByteArray("30ef026f687d0c55687d0c55687d0c55"));
            Assert.AreEqual(id1_verified, id1);

            builder = new ObjectIdBuilder();
            buffer = ASCIIEncoding.ASCII.GetBytes("this is a test of a longer string");
            builder.Write(buffer, 0, buffer.Length);
            var id2 = builder.ComputeHash();
            var id2_verified = new ObjectId(StringToByteArray("eb221d36fbd7e7bfd3ab4fd02fa6482b"));
            Assert.AreEqual(id2_verified, id2);
        }
Esempio n. 10
0
        public void TestSimple()
        {
            var builder = new ObjectIdBuilder();
            var buffer  = ASCIIEncoding.ASCII.GetBytes("0123456789ABCDEF"); // 16 bytes

            builder.Write(buffer, 0, buffer.Length);
            var id1 = builder.ComputeHash();

            // The ObjectIdSimpleBuilder must be identical to the ObjectIdBuilder when data length is module of 16 bytes
            var simpleBuilder = new ObjectIdSimpleBuilder();

            simpleBuilder.Write(BitConverter.ToInt32(ASCIIEncoding.ASCII.GetBytes("0123"), 0));
            simpleBuilder.Write(BitConverter.ToInt32(ASCIIEncoding.ASCII.GetBytes("4567"), 0));
            simpleBuilder.Write(BitConverter.ToInt32(ASCIIEncoding.ASCII.GetBytes("89AB"), 0));
            simpleBuilder.Write(BitConverter.ToInt32(ASCIIEncoding.ASCII.GetBytes("CDEF"), 0));
            var id2 = simpleBuilder.ComputeHash();

            Assert.Equal(id1, id2);
        }
Esempio n. 11
0
        public void TestFull()
        {
            var builder = new ObjectIdBuilder();
            var buffer  = ASCIIEncoding.ASCII.GetBytes("test");

            builder.Write(buffer, 0, buffer.Length);
            var id1          = builder.ComputeHash();
            var id1_verified = new ObjectId(StringToByteArray("30ef026f687d0c55687d0c55687d0c55"));

            Assert.Equal(id1_verified, id1);

            builder = new ObjectIdBuilder();
            buffer  = ASCIIEncoding.ASCII.GetBytes("this is a test of a longer string");
            builder.Write(buffer, 0, buffer.Length);
            var id2          = builder.ComputeHash();
            var id2_verified = new ObjectId(StringToByteArray("eb221d36fbd7e7bfd3ab4fd02fa6482b"));

            Assert.Equal(id2_verified, id2);
        }
Esempio n. 12
0
        private static void HashType(ObjectIdBuilder hashBuilder, EffectTypeDescription type)
        {
            hashBuilder.Write(type.RowCount);
            hashBuilder.Write(type.ColumnCount);
            hashBuilder.Write(type.Elements);
            if (type.Name != null)
            {
                hashBuilder.Write(type.Name);
            }

            if (type.Members != null)
            {
                foreach (var member in type.Members)
                {
                    hashBuilder.Write(member.Name);
                    hashBuilder.Write(member.Offset);
                    HashType(hashBuilder, member.Type);
                }
            }
        }
Esempio n. 13
0
 public static unsafe void Write(this ObjectIdBuilder objectIdBuilder, bool b)
 {
     objectIdBuilder.WriteByte((byte)(b ? 1 : 0));
 }
Esempio n. 14
0
 public static unsafe void Write(this ObjectIdBuilder objectIdBuilder, int i)
 {
     objectIdBuilder.Write((byte *)&i, sizeof(int));
 }
Esempio n. 15
0
        /// <summary>
        ///   Generates serializer code using Cecil.
        /// </summary>
        /// <param name="registry"></param>
        private static void GenerateSerializerCode(ComplexSerializerRegistry registry, out ObjectId serializationHash)
        {
            var hash = new ObjectIdBuilder();

            // First, hash global binary format version, in case it gets bumped
            hash.Write(DataSerializer.BinaryFormatVersion);

            var assembly         = registry.Assembly;
            var strideCoreModule = assembly.GetStrideCoreModule();

            var dataSerializerTypeRef              = assembly.MainModule.ImportReference(strideCoreModule.GetType("Stride.Core.Serialization.DataSerializer`1"));
            var serializerSelectorType             = strideCoreModule.GetType("Stride.Core.Serialization.SerializerSelector");
            var serializerSelectorTypeRef          = assembly.MainModule.ImportReference(serializerSelectorType);
            var serializerSelectorGetSerializerRef = assembly.MainModule.ImportReference(serializerSelectorType.Methods.Single(x => x.Name == "GetSerializer" && x.Parameters.Count == 0 && x.GenericParameters.Count == 1));
            var memberSerializerCreateRef          = assembly.MainModule.ImportReference(strideCoreModule.GetType("Stride.Core.Serialization.MemberSerializer`1").Methods.Single(x => x.Name == "Create"));

            var dataSerializerSerializeMethod    = dataSerializerTypeRef.Resolve().Methods.Single(x => x.Name == "Serialize" && (x.Attributes & MethodAttributes.Abstract) != 0);
            var dataSerializerSerializeMethodRef = assembly.MainModule.ImportReference(dataSerializerSerializeMethod);

            // Generate serializer code for each type (we generate code similar to ComplexClassSerializerGenerator.tt, see this file for reference)
            foreach (var complexType in registry.Context.ComplexTypes)
            {
                var type              = complexType.Key;
                var serializerType    = (TypeDefinition)complexType.Value.SerializerType;
                var genericParameters = serializerType.GenericParameters.ToArray <TypeReference>();
                var typeWithGenerics  = type.MakeGenericType(genericParameters);

                // Hash
                hash.Write(typeWithGenerics.FullName);

                TypeReference   parentType            = null;
                FieldDefinition parentSerializerField = null;
                if (complexType.Value.IsComplexSerializerProcessParentType)
                {
                    parentType = ResolveGenericsVisitor.Process(serializerType, type.BaseType);
                    serializerType.Fields.Add(parentSerializerField = new FieldDefinition("parentSerializer", Mono.Cecil.FieldAttributes.Private, dataSerializerTypeRef.MakeGenericType(parentType)));

                    hash.Write("parent");
                }

                var serializableItems     = ComplexSerializerRegistry.GetSerializableItems(type).ToArray();
                var serializableItemInfos = new Dictionary <TypeReference, (FieldDefinition SerializerField, TypeReference Type)>(TypeReferenceEqualityComparer.Default);
                var localsByTypes         = new Dictionary <TypeReference, VariableDefinition>(TypeReferenceEqualityComparer.Default);

                ResolveGenericsVisitor genericResolver = null;
                if (type.HasGenericParameters)
                {
                    var genericMapping = new Dictionary <TypeReference, TypeReference>();
                    for (int i = 0; i < type.GenericParameters.Count; i++)
                    {
                        genericMapping[type.GenericParameters[i]] = serializerType.GenericParameters[i];
                    }
                    genericResolver = new ResolveGenericsVisitor(genericMapping);
                }

                foreach (var serializableItem in serializableItems)
                {
                    if (serializableItemInfos.ContainsKey(serializableItem.Type))
                    {
                        continue;
                    }

                    var serializableItemType = serializableItem.Type;
                    if (genericResolver != null)
                    {
                        serializableItemType = genericResolver.VisitDynamic(serializableItemType);
                    }
                    var fieldDefinition = new FieldDefinition($"{Utilities.BuildValidClassName(serializableItemType.FullName)}Serializer", Mono.Cecil.FieldAttributes.Private, dataSerializerTypeRef.MakeGenericType(serializableItemType));
                    serializableItemInfos.Add(serializableItem.Type, (fieldDefinition, serializableItemType));
                    serializerType.Fields.Add(fieldDefinition);

                    hash.Write(serializableItem.Type.FullName);
                    hash.Write(serializableItem.Name);
                    hash.Write(serializableItem.AssignBack);
                }

                // Add constructor (call parent constructor)
                var ctor = new MethodDefinition(".ctor",
                                                MethodAttributes.RTSpecialName | MethodAttributes.SpecialName | MethodAttributes.HideBySig |
                                                MethodAttributes.Public, assembly.MainModule.TypeSystem.Void);
                ctor.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_0));
                ctor.Body.Instructions.Add(Instruction.Create(OpCodes.Call, assembly.MainModule.ImportReference(serializerType.BaseType.Resolve().GetEmptyConstructor(true)).MakeGeneric(typeWithGenerics)));
                ctor.Body.Instructions.Add(Instruction.Create(OpCodes.Ret));
                serializerType.Methods.Add(ctor);

                // Add Initialize method
                var initialize = new MethodDefinition("Initialize", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual, assembly.MainModule.TypeSystem.Void);
                initialize.Parameters.Add(new ParameterDefinition("serializerSelector", ParameterAttributes.None, serializerSelectorTypeRef));
                if (complexType.Value.IsComplexSerializerProcessParentType)
                {
                    initialize.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_0));
                    initialize.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_1));
                    initialize.Body.Instructions.Add(Instruction.Create(OpCodes.Callvirt, serializerSelectorGetSerializerRef.MakeGenericMethod(parentType)));
                    initialize.Body.Instructions.Add(Instruction.Create(OpCodes.Stfld, parentSerializerField.MakeGeneric(genericParameters)));
                }
                foreach (var serializableItem in serializableItemInfos)
                {
                    initialize.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_0));
                    initialize.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_1));
                    initialize.Body.Instructions.Add(Instruction.Create(OpCodes.Ldc_I4_1));
                    initialize.Body.Instructions.Add(Instruction.Create(OpCodes.Call, memberSerializerCreateRef.MakeGeneric(serializableItem.Value.Type)));
                    initialize.Body.Instructions.Add(Instruction.Create(OpCodes.Stfld, serializableItem.Value.SerializerField.MakeGeneric(genericParameters)));
                }
                initialize.Body.Instructions.Add(Instruction.Create(OpCodes.Ret));
                serializerType.Methods.Add(initialize);

                // Add Serialize method
                var serialize = new MethodDefinition("Serialize", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual, assembly.MainModule.TypeSystem.Void);
                serialize.Parameters.Add(new ParameterDefinition("obj", ParameterAttributes.None, typeWithGenerics.MakeByReferenceType()));
                // Copy other parameters from parent method
                for (int i = 1; i < dataSerializerSerializeMethod.Parameters.Count; ++i)
                {
                    var parentParameter = dataSerializerSerializeMethod.Parameters[i];
                    serialize.Parameters.Add(new ParameterDefinition(parentParameter.Name, ParameterAttributes.None, assembly.MainModule.ImportReference(parentParameter.ParameterType)));
                }

                if (complexType.Value.IsComplexSerializerProcessParentType)
                {
                    serialize.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_0));
                    serialize.Body.Instructions.Add(Instruction.Create(OpCodes.Ldfld, parentSerializerField.MakeGeneric(genericParameters)));
                    serialize.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_1));
                    serialize.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_2));
                    serialize.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_3));
                    serialize.Body.Instructions.Add(Instruction.Create(OpCodes.Callvirt, dataSerializerSerializeMethodRef.MakeGeneric(parentType)));
                }

                if (serializableItems.Length > 0)
                {
                    var blockStartInstructions = new[] { Instruction.Create(OpCodes.Nop), Instruction.Create(OpCodes.Nop) };
                    // Iterate over ArchiveMode
                    for (int i = 0; i < 2; ++i)
                    {
                        var archiveMode = i == 0 ? ArchiveMode.Serialize : ArchiveMode.Deserialize;

                        // Check mode
                        if (archiveMode == ArchiveMode.Serialize)
                        {
                            serialize.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_2));
                            serialize.Body.Instructions.Add(Instruction.Create(OpCodes.Ldc_I4, (int)archiveMode));
                            serialize.Body.Instructions.Add(Instruction.Create(OpCodes.Ceq));
                            serialize.Body.Instructions.Add(Instruction.Create(OpCodes.Brfalse, blockStartInstructions[0]));
                        }
                        else
                        {
                            serialize.Body.Instructions.Add(blockStartInstructions[0]);
                        }

                        foreach (var serializableItem in serializableItems)
                        {
                            if (serializableItem.HasFixedAttribute)
                            {
                                throw new NotImplementedException("FixedBuffer attribute is not supported.");
                            }

                            var memberAssignBack     = serializableItem.AssignBack;
                            var memberVariableName   = (serializableItem.MemberInfo is PropertyDefinition || !memberAssignBack) ? ComplexSerializerRegistry.CreateMemberVariableName(serializableItem.MemberInfo) : null;
                            var serializableItemInfo = serializableItemInfos[serializableItem.Type];
                            serialize.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_0));
                            serialize.Body.Instructions.Add(Instruction.Create(OpCodes.Ldfld, serializableItemInfo.SerializerField.MakeGeneric(genericParameters)));

                            var fieldReference = serializableItem.MemberInfo is FieldReference?assembly.MainModule.ImportReference((FieldReference)serializableItem.MemberInfo).MakeGeneric(genericParameters) : null;

                            if (memberVariableName != null)
                            {
                                // Use a temporary variable
                                if (!localsByTypes.TryGetValue(serializableItemInfo.Type, out var tempLocal))
                                {
                                    tempLocal = new VariableDefinition(serializableItemInfo.Type);
                                    localsByTypes.Add(serializableItemInfo.Type, tempLocal);
                                    serialize.Body.Variables.Add(tempLocal);
                                    serialize.Body.InitLocals = true;
                                }

                                if (!(archiveMode == ArchiveMode.Deserialize && memberAssignBack))
                                {
                                    // obj.Member
                                    serialize.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_1));
                                    if (!type.IsValueType)
                                    {
                                        serialize.Body.Instructions.Add(Instruction.Create(OpCodes.Ldind_Ref));
                                    }

                                    if (serializableItem.MemberInfo is PropertyDefinition property)
                                    {
                                        var getMethod = property.Resolve().GetMethod;
                                        serialize.Body.Instructions.Add(Instruction.Create(getMethod.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, assembly.MainModule.ImportReference(getMethod).MakeGeneric(genericParameters)));
                                    }
                                    else if (serializableItem.MemberInfo is FieldDefinition)
                                    {
                                        serialize.Body.Instructions.Add(Instruction.Create(OpCodes.Ldfld, fieldReference));
                                    }
                                    serialize.Body.Instructions.Add(Instruction.Create(OpCodes.Stloc, tempLocal));
                                    serialize.Body.Instructions.Add(Instruction.Create(OpCodes.Ldloca, tempLocal));
                                }
                                else
                                {
                                    // default(T)
                                    serialize.Body.Instructions.Add(Instruction.Create(OpCodes.Ldloca, tempLocal));
                                    serialize.Body.Instructions.Add(Instruction.Create(OpCodes.Dup));
                                    serialize.Body.Instructions.Add(Instruction.Create(OpCodes.Initobj, serializableItemInfo.Type));
                                }
                            }
                            else
                            {
                                // Use object directly
                                serialize.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_1));
                                if (!type.IsValueType)
                                {
                                    serialize.Body.Instructions.Add(Instruction.Create(OpCodes.Ldind_Ref));
                                }
                                serialize.Body.Instructions.Add(Instruction.Create(OpCodes.Ldflda, fieldReference));
                            }
                            serialize.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_2));
                            serialize.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_3));

                            serialize.Body.Instructions.Add(Instruction.Create(OpCodes.Callvirt, dataSerializerSerializeMethodRef.MakeGeneric(serializableItemInfo.Type)));

                            if (archiveMode == ArchiveMode.Deserialize && memberVariableName != null && memberAssignBack)
                            {
                                // Need to copy back to object
                                serialize.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_1));
                                if (!type.IsValueType)
                                {
                                    serialize.Body.Instructions.Add(Instruction.Create(OpCodes.Ldind_Ref));
                                }

                                serialize.Body.Instructions.Add(Instruction.Create(OpCodes.Ldloc, localsByTypes[serializableItemInfo.Type]));

                                if (serializableItem.MemberInfo is PropertyDefinition property)
                                {
                                    var setMethod = property.Resolve().SetMethod;
                                    serialize.Body.Instructions.Add(Instruction.Create(setMethod.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, assembly.MainModule.ImportReference(setMethod).MakeGeneric(genericParameters)));
                                }
                                else if (serializableItem.MemberInfo is FieldDefinition)
                                {
                                    serialize.Body.Instructions.Add(Instruction.Create(OpCodes.Stfld, fieldReference));
                                }
                            }
                        }

                        if (archiveMode == ArchiveMode.Serialize)
                        {
                            serialize.Body.Instructions.Add(Instruction.Create(OpCodes.Br, blockStartInstructions[1]));
                        }
                    }

                    serialize.Body.Instructions.Add(blockStartInstructions[1]);
                }
                serialize.Body.Instructions.Add(Instruction.Create(OpCodes.Ret));
                serializerType.Methods.Add(serialize);

                //assembly.MainModule.Types.Add(serializerType);
            }

            var mscorlibAssembly   = CecilExtensions.FindCorlibAssembly(assembly);
            var reflectionAssembly = CecilExtensions.FindReflectionAssembly(assembly);

            // String
            var stringType    = mscorlibAssembly.MainModule.GetTypeResolved(typeof(string).FullName);
            var stringTypeRef = assembly.MainModule.ImportReference(stringType);
            // Type
            var typeType                = mscorlibAssembly.MainModule.GetTypeResolved(typeof(Type).FullName);
            var typeTypeRef             = assembly.MainModule.ImportReference(typeType);
            var getTypeFromHandleMethod = typeType.Methods.First(x => x.Name == nameof(Type.GetTypeFromHandle));
            var getTokenInfoExMethod    = reflectionAssembly.MainModule.GetTypeResolved("System.Reflection.IntrospectionExtensions").Resolve().Methods.First(x => x.Name == nameof(IntrospectionExtensions.GetTypeInfo));
            var typeInfoType            = reflectionAssembly.MainModule.GetTypeResolved(typeof(TypeInfo).FullName);
            // NOTE: TypeInfo.Assembly/Module could be on the type itself or on its parent MemberInfo depending on runtime
            var getTypeInfoAssembly    = typeInfoType.Properties.Concat(typeInfoType.BaseType.Resolve().Properties).First(x => x.Name == nameof(TypeInfo.Assembly)).GetMethod;
            var getTypeInfoModule      = typeInfoType.Properties.Concat(typeInfoType.BaseType.Resolve().Properties).First(x => x.Name == nameof(TypeInfo.Module)).GetMethod;
            var typeHandleProperty     = typeType.Properties.First(x => x.Name == nameof(Type.TypeHandle));
            var getTypeHandleMethodRef = assembly.MainModule.ImportReference(typeHandleProperty.GetMethod);

            // Generate code
            var serializerFactoryType = new TypeDefinition("Stride.Core.DataSerializers",
                                                           Utilities.BuildValidClassName(assembly.Name.Name) + "SerializerFactory",
                                                           TypeAttributes.BeforeFieldInit | TypeAttributes.AnsiClass | TypeAttributes.AutoClass |
                                                           TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.Abstract,
                                                           assembly.MainModule.TypeSystem.Object);

            assembly.MainModule.Types.Add(serializerFactoryType);

            var dataSerializerModeTypeRef = assembly.MainModule.ImportReference(strideCoreModule.GetType("Stride.Core.Serialization.DataSerializerGenericMode"));

            var dataSerializerGlobalAttribute = strideCoreModule.GetType("Stride.Core.Serialization.DataSerializerGlobalAttribute");
            var dataSerializerGlobalCtorRef   = assembly.MainModule.ImportReference(dataSerializerGlobalAttribute.GetConstructors().Single(x => !x.IsStatic && x.Parameters.Count == 5));

            foreach (var profile in registry.Context.SerializableTypesProfiles)
            {
                foreach (var type in profile.Value.SerializableTypes.Where(x => x.Value.IsLocal))
                {
                    // Generating: [DataSerializerGlobalAttribute(<#= type.Value.SerializerType != null ? $"typeof({type.Value.SerializerType.ConvertCSharp(false)})" : "null" #>, typeof(<#= type.Key.ConvertCSharp(false) #>), DataSerializerGenericMode.<#= type.Value.Mode.ToString() #>, <#=type.Value.Inherited ? "true" : "false"#>, <#=type.Value.ComplexSerializer ? "true" : "false"#>, Profile = "<#=profile.Key#>")]
                    serializerFactoryType.CustomAttributes.Add(new CustomAttribute(dataSerializerGlobalCtorRef)
                    {
                        ConstructorArguments =
                        {
                            new CustomAttributeArgument(typeTypeRef,                            type.Value.SerializerType != null ? assembly.MainModule.ImportReference(type.Value.SerializerType) : null),
                            new CustomAttributeArgument(typeTypeRef,                            assembly.MainModule.ImportReference(type.Key)),
                            new CustomAttributeArgument(dataSerializerModeTypeRef,              type.Value.GenericsMode),
                            new CustomAttributeArgument(assembly.MainModule.TypeSystem.Boolean, type.Value.IsInherited),
                            new CustomAttributeArgument(assembly.MainModule.TypeSystem.Boolean, type.Value.IsComplexSerializer),
                        },
                        Properties =
                        {
                            new CustomAttributeNamedArgument("Profile", new CustomAttributeArgument(assembly.MainModule.TypeSystem.String, profile.Key))
                        },
                    });
                }
                foreach (var type in profile.Value.GenericSerializableTypes.Where(x => x.Value.IsLocal))
                {
                    // Generating: [DataSerializerGlobalAttribute(<#= type.Value.SerializerType != null ? $"typeof({type.Value.SerializerType.ConvertCSharp(true)})" : "null" #>, typeof(<#= type.Key.ConvertCSharp(true) #>), DataSerializerGenericMode.<#= type.Value.Mode.ToString() #>, <#=type.Value.Inherited ? "true" : "false"#>, <#=type.Value.ComplexSerializer ? "true" : "false"#>, Profile = "<#=profile.Key#>")]
                    serializerFactoryType.CustomAttributes.Add(new CustomAttribute(dataSerializerGlobalCtorRef)
                    {
                        ConstructorArguments =
                        {
                            new CustomAttributeArgument(typeTypeRef,                            type.Value.SerializerType != null ? assembly.MainModule.ImportReference(type.Value.SerializerType) : null),
                            new CustomAttributeArgument(typeTypeRef,                            assembly.MainModule.ImportReference(type.Key)),
                            new CustomAttributeArgument(dataSerializerModeTypeRef,              type.Value.GenericsMode),
                            new CustomAttributeArgument(assembly.MainModule.TypeSystem.Boolean, type.Value.IsInherited),
                            new CustomAttributeArgument(assembly.MainModule.TypeSystem.Boolean, type.Value.IsComplexSerializer),
                        },
                        Properties =
                        {
                            new CustomAttributeNamedArgument("Profile", new CustomAttributeArgument(assembly.MainModule.TypeSystem.String, profile.Key))
                        },
                    });
                }
            }

            // Create Initialize method
            var initializeMethod = new MethodDefinition("Initialize",
                                                        MethodAttributes.Assembly | MethodAttributes.HideBySig | MethodAttributes.Static,
                                                        assembly.MainModule.TypeSystem.Void);

            serializerFactoryType.Methods.Add(initializeMethod);

            // Make sure it is called at module startup
            initializeMethod.AddModuleInitializer(-1000);

            var initializeMethodIL = initializeMethod.Body.GetILProcessor();

            // Generating: var assemblySerializers = new AssemblySerializers(typeof(<#=registry.ClassName#>).GetTypeInfo().Assembly);
            var assemblySerializersType = strideCoreModule.GetType("Stride.Core.Serialization.AssemblySerializers");

            var assemblySerializersGetDataContractAliasesRef = assembly.MainModule.ImportReference(assemblySerializersType.Properties.First(x => x.Name == "DataContractAliases").GetMethod);
            var assemblySerializersGetDataContractAliasesAdd = assemblySerializersGetDataContractAliasesRef.ReturnType.Resolve().Methods.First(x => x.Name == "Add");
            var dataContractAliasTypeRef     = ((GenericInstanceType)assemblySerializersGetDataContractAliasesRef.ReturnType).GenericArguments[0];
            var dataContractAliasTypeCtorRef = assembly.MainModule.ImportReference(dataContractAliasTypeRef.Resolve().GetConstructors().Single());
            var assemblySerializersGetDataContractAliasesAddRef = assembly.MainModule.ImportReference(assemblySerializersGetDataContractAliasesAdd).MakeGeneric(dataContractAliasTypeRef);

            initializeMethodIL.Emit(OpCodes.Ldtoken, serializerFactoryType);
            initializeMethodIL.Emit(OpCodes.Call, assembly.MainModule.ImportReference(getTypeFromHandleMethod));
            initializeMethodIL.Emit(OpCodes.Call, assembly.MainModule.ImportReference(getTokenInfoExMethod));
            initializeMethodIL.Emit(OpCodes.Callvirt, assembly.MainModule.ImportReference(getTypeInfoAssembly));
            initializeMethodIL.Emit(OpCodes.Newobj, assembly.MainModule.ImportReference(assemblySerializersType.Methods.Single(x => x.IsConstructor && x.Parameters.Count == 1)));

            foreach (var alias in registry.Context.DataContractAliases)
            {
                initializeMethodIL.Emit(OpCodes.Dup);

                // Generating: assemblySerializers.DataContractAliases.Add(new AssemblySerializers.DataContractAlias(@"<#= alias.Item1 #>", typeof(<#= alias.Item2.ConvertCSharp(true) #>), <#=alias.Item3 ? "true" : "false"#>));
                initializeMethodIL.Emit(OpCodes.Call, assemblySerializersGetDataContractAliasesRef);
                initializeMethodIL.Emit(OpCodes.Ldstr, alias.Item1);
                initializeMethodIL.Emit(OpCodes.Ldtoken, assembly.MainModule.ImportReference(alias.Item2));
                initializeMethodIL.Emit(OpCodes.Call, assembly.MainModule.ImportReference(getTypeFromHandleMethod));
                initializeMethodIL.Emit(alias.Item3 ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
                initializeMethodIL.Emit(OpCodes.Newobj, dataContractAliasTypeCtorRef);
                initializeMethodIL.Emit(OpCodes.Call, assemblySerializersGetDataContractAliasesAddRef);
            }

            var assemblySerializersGetModulesRef = assembly.MainModule.ImportReference(assemblySerializersType.Properties.First(x => x.Name == "Modules").GetMethod);
            var assemblySerializersGetModulesAdd = assemblySerializersGetModulesRef.ReturnType.Resolve().Methods.First(x => x.Name == "Add");
            var moduleRef = ((GenericInstanceType)assemblySerializersGetModulesRef.ReturnType).GenericArguments[0];
            var assemblySerializersGetModulesAddRef = assembly.MainModule.ImportReference(assemblySerializersGetModulesAdd).MakeGeneric(moduleRef);

            foreach (var referencedAssemblySerializerFactoryType in registry.ReferencedAssemblySerializerFactoryTypes)
            {
                initializeMethodIL.Emit(OpCodes.Dup);

                // Generating: assemblySerializers.Modules.Add(typeof(<#=referencedAssemblySerializerFactoryType.ConvertCSharp()#>).GetTypeInfo().Module);
                initializeMethodIL.Emit(OpCodes.Call, assemblySerializersGetModulesRef);
                initializeMethodIL.Emit(OpCodes.Ldtoken, assembly.MainModule.ImportReference(referencedAssemblySerializerFactoryType));
                initializeMethodIL.Emit(OpCodes.Call, assembly.MainModule.ImportReference(getTypeFromHandleMethod));
                initializeMethodIL.Emit(OpCodes.Call, assembly.MainModule.ImportReference(getTokenInfoExMethod));
                initializeMethodIL.Emit(OpCodes.Callvirt, assembly.MainModule.ImportReference(getTypeInfoModule));
                initializeMethodIL.Emit(OpCodes.Call, assemblySerializersGetModulesAddRef);
            }

            var objectIdCtorRef                          = assembly.MainModule.ImportReference(strideCoreModule.GetType("Stride.Core.Storage.ObjectId").GetConstructors().Single(x => x.Parameters.Count == 4));
            var serializerEntryTypeCtorRef               = assembly.MainModule.ImportReference(strideCoreModule.GetType("Stride.Core.Serialization.AssemblySerializerEntry").GetConstructors().Single());
            var assemblySerializersPerProfileType        = strideCoreModule.GetType("Stride.Core.Serialization.AssemblySerializersPerProfile");
            var assemblySerializersPerProfileTypeAddRef  = assembly.MainModule.ImportReference(assemblySerializersPerProfileType.BaseType.Resolve().Methods.First(x => x.Name == "Add")).MakeGeneric(serializerEntryTypeCtorRef.DeclaringType);
            var assemblySerializersPerProfileTypeCtorRef = assembly.MainModule.ImportReference(assemblySerializersPerProfileType.GetEmptyConstructor());
            var assemblySerializersGetProfilesRef        = assembly.MainModule.ImportReference(assemblySerializersType.Properties.First(x => x.Name == "Profiles").GetMethod);
            var assemblySerializersGetProfilesSetItemRef = assembly.MainModule.ImportReference(assemblySerializersGetProfilesRef.ReturnType.Resolve().Methods.First(x => x.Name == "set_Item"))
                                                           .MakeGeneric(((GenericInstanceType)assemblySerializersGetProfilesRef.ReturnType).GenericArguments.ToArray());

            var runtimeHelpersType        = mscorlibAssembly.MainModule.GetTypeResolved(typeof(RuntimeHelpers).FullName);
            var runClassConstructorMethod = assembly.MainModule.ImportReference(runtimeHelpersType.Methods.Single(x => x.IsPublic && x.Name == "RunClassConstructor" && x.Parameters.Count == 1 && x.Parameters[0].ParameterType.FullName == typeof(RuntimeTypeHandle).FullName));

            foreach (var profile in registry.Context.SerializableTypesProfiles)
            {
                initializeMethodIL.Emit(OpCodes.Dup);

                // Generating: var assemblySerializersProfile = new AssemblySerializersPerProfile();
                // Generating: assemblySerializers.Profiles["<#=profile.Key#>"] = assemblySerializersProfile;
                initializeMethodIL.Emit(OpCodes.Callvirt, assemblySerializersGetProfilesRef);
                initializeMethodIL.Emit(OpCodes.Ldstr, profile.Key);
                initializeMethodIL.Emit(OpCodes.Newobj, assemblySerializersPerProfileTypeCtorRef);

                foreach (var type in profile.Value.SerializableTypes.Where(x => x.Value.IsLocal))
                {
                    // Generating: assemblySerializersProfile.Add(new AssemblySerializerEntry(<#=type.Key.ConvertTypeId()#>, typeof(<#= type.Key.ConvertCSharp() #>), <# if (type.Value.SerializerType != null) { #>typeof(<#= type.Value.SerializerType.ConvertCSharp() #>)<# } else { #>null<# } #>));
                    initializeMethodIL.Emit(OpCodes.Dup);

                    var typeName = type.Key.ConvertToValidCSharp(false);
                    var typeId   = ObjectId.FromBytes(Encoding.UTF8.GetBytes(typeName));

                    unsafe
                    {
                        var typeIdHash = (int *)&typeId;

                        for (int i = 0; i < ObjectId.HashSize / 4; ++i)
                        {
                            initializeMethodIL.Emit(OpCodes.Ldc_I4, typeIdHash[i]);
                        }
                    }

                    initializeMethodIL.Emit(OpCodes.Newobj, objectIdCtorRef);

                    initializeMethodIL.Emit(OpCodes.Ldtoken, assembly.MainModule.ImportReference(type.Key));
                    initializeMethodIL.Emit(OpCodes.Call, assembly.MainModule.ImportReference(getTypeFromHandleMethod));

                    if (type.Value.SerializerType != null)
                    {
                        initializeMethodIL.Emit(OpCodes.Ldtoken, assembly.MainModule.ImportReference(type.Value.SerializerType));
                        initializeMethodIL.Emit(OpCodes.Call, assembly.MainModule.ImportReference(getTypeFromHandleMethod));
                    }
                    else
                    {
                        initializeMethodIL.Emit(OpCodes.Ldnull);
                    }

                    initializeMethodIL.Emit(OpCodes.Newobj, serializerEntryTypeCtorRef);
                    initializeMethodIL.Emit(OpCodes.Callvirt, assemblySerializersPerProfileTypeAddRef);

                    if (type.Value.SerializerType?.Resolve()?.Methods.Any(x => x.IsConstructor && x.IsStatic) == true)
                    {
                        // Generating: System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(typeof(<#=type.Value.SerializerType.ConvertCSharp()#>).TypeHandle);
                        initializeMethodIL.Append(Instruction.Create(OpCodes.Ldtoken, type.Value.SerializerType));
                        initializeMethodIL.Append(Instruction.Create(OpCodes.Call, assembly.MainModule.ImportReference(getTypeFromHandleMethod)));
                        initializeMethodIL.Append(Instruction.Create(OpCodes.Callvirt, getTypeHandleMethodRef));
                        initializeMethodIL.Append(Instruction.Create(OpCodes.Call, runClassConstructorMethod));
                    }
                }

                initializeMethodIL.Emit(OpCodes.Callvirt, assemblySerializersGetProfilesSetItemRef);
            }

            // Generating: DataSerializerFactory.RegisterSerializationAssembly(assemblySerializers);
            var dataSerializerFactoryRegisterSerializationAssemblyMethodRef = assembly.MainModule.ImportReference(strideCoreModule.GetType("Stride.Core.Serialization.DataSerializerFactory").Methods.Single(x => x.Name == "RegisterSerializationAssembly" && x.Parameters[0].ParameterType.FullName == assemblySerializersType.FullName));

            initializeMethodIL.Emit(OpCodes.Call, dataSerializerFactoryRegisterSerializationAssemblyMethodRef);

            // Generating: AssemblyRegistry.Register(typeof(<#=registry.ClassName#>).GetTypeInfo().Assembly, AssemblyCommonCategories.Engine);
            initializeMethodIL.Emit(OpCodes.Ldtoken, serializerFactoryType);
            initializeMethodIL.Emit(OpCodes.Call, assembly.MainModule.ImportReference(getTypeFromHandleMethod));
            initializeMethodIL.Emit(OpCodes.Call, assembly.MainModule.ImportReference(getTokenInfoExMethod));
            initializeMethodIL.Emit(OpCodes.Callvirt, assembly.MainModule.ImportReference(getTypeInfoAssembly));

            // create new[] { AssemblyCommonCategories.Engine }
            initializeMethodIL.Emit(OpCodes.Ldc_I4_1);
            initializeMethodIL.Emit(OpCodes.Newarr, assembly.MainModule.TypeSystem.String);
            initializeMethodIL.Emit(OpCodes.Dup);
            initializeMethodIL.Emit(OpCodes.Ldc_I4_0);
            initializeMethodIL.Emit(OpCodes.Ldstr, Core.Reflection.AssemblyCommonCategories.Engine);
            initializeMethodIL.Emit(OpCodes.Stelem_Ref);

            var assemblyRegistryRegisterMethodRef = assembly.MainModule.ImportReference(strideCoreModule.GetType("Stride.Core.Reflection.AssemblyRegistry").Methods.Single(x => x.Name == "Register" && x.Parameters[1].ParameterType.IsArray));

            initializeMethodIL.Emit(OpCodes.Call, assemblyRegistryRegisterMethodRef);

            initializeMethodIL.Emit(OpCodes.Ret);

            // Add AssemblySerializerFactoryAttribute
            var assemblySerializerFactoryAttribute = strideCoreModule.GetType("Stride.Core.Serialization.AssemblySerializerFactoryAttribute");

            assembly.CustomAttributes.Add(new CustomAttribute(assembly.MainModule.ImportReference(assemblySerializerFactoryAttribute.GetEmptyConstructor()))
            {
                Fields =
                {
                    new CustomAttributeNamedArgument("Type", new CustomAttributeArgument(typeTypeRef, serializerFactoryType)),
                }
            });

            serializationHash = hash.ComputeHash();
        }
        internal LogicalGroup CreateLogicalGroup(string name)
        {
            var logicalGroup = new LogicalGroup
            {
                DescriptorEntryStart = -1,
                ConstantBufferMemberStart = -1,
            };

            var hashBuilder = new ObjectIdBuilder();

            for (int index = 0; index < ConstantBufferReflection.Members.Length; index++)
            {
                var member = ConstantBufferReflection.Members[index];
                if (member.LogicalGroup == name)
                {
                    // First item?
                    if (logicalGroup.ConstantBufferMemberStart == -1)
                    {
                        logicalGroup.ConstantBufferOffset = member.Offset;
                        logicalGroup.ConstantBufferMemberStart = index;
                    }

                    // Update count
                    logicalGroup.ConstantBufferMemberCount = index + 1 - logicalGroup.ConstantBufferMemberStart;
                    logicalGroup.ConstantBufferSize = member.Offset + member.Size - logicalGroup.ConstantBufferOffset;

                    // Hash
                    Effect.HashConstantBufferMember(ref hashBuilder, ref member);
                }
                else if (logicalGroup.ConstantBufferMemberStart != -1)
                    break; // group is finished, no need to scan the end
            }

            for (int index = 0, slot = 0; index < DescriptorSetLayoutBuilder.Entries.Count; index++)
            {
                var descriptorSetEntry = DescriptorSetLayoutBuilder.Entries[index];
                if (descriptorSetEntry.LogicalGroup == name)
                {
                    // First item?
                    if (logicalGroup.DescriptorEntryStart == -1)
                    {
                        logicalGroup.DescriptorSlotStart = slot;
                        logicalGroup.DescriptorEntryStart = index;
                    }

                    // Update count
                    logicalGroup.DescriptorEntryCount = index + 1 - logicalGroup.DescriptorEntryStart;
                    logicalGroup.DescriptorSlotCount += descriptorSetEntry.ArraySize;

                    // Hash
                    hashBuilder.Write(descriptorSetEntry.Key.Name);
                    hashBuilder.Write(descriptorSetEntry.Class);
                    hashBuilder.Write(descriptorSetEntry.ArraySize);
                }
                else if (logicalGroup.DescriptorEntryStart != -1)
                    break; // group is finished, no need to scan the end

                slot += descriptorSetEntry.ArraySize;
            }

            logicalGroup.Hash = hashBuilder.ComputeHash();

            return logicalGroup;
        }
Esempio n. 17
0
        private unsafe void UpdateName()
        {
            fixed (char* bufferStart = Name)
            {
                var objectIdBuilder = new ObjectIdBuilder();
                objectIdBuilder.Write((byte*)bufferStart, sizeof(char) * Name.Length);

                var objId = objectIdBuilder.ComputeHash();
                var objIdData = (ulong*)&objId;
                HashCode = objIdData[0] ^ objIdData[1];
            }
        }
Esempio n. 18
0
        internal LogicalGroup CreateLogicalGroup(string name)
        {
            var logicalGroup = new LogicalGroup
            {
                DescriptorEntryStart      = -1,
                ConstantBufferMemberStart = -1,
            };

            var hashBuilder = new ObjectIdBuilder();

            for (int index = 0; index < ConstantBufferReflection.Members.Length; index++)
            {
                var member = ConstantBufferReflection.Members[index];
                if (member.LogicalGroup == name)
                {
                    // First item?
                    if (logicalGroup.ConstantBufferMemberStart == -1)
                    {
                        logicalGroup.ConstantBufferOffset      = member.Offset;
                        logicalGroup.ConstantBufferMemberStart = index;
                    }

                    // Update count
                    logicalGroup.ConstantBufferMemberCount = index + 1 - logicalGroup.ConstantBufferMemberStart;
                    logicalGroup.ConstantBufferSize        = member.Offset + member.Size - logicalGroup.ConstantBufferOffset;

                    // Hash
                    Effect.HashConstantBufferMember(ref hashBuilder, ref member, logicalGroup.ConstantBufferOffset);
                }
                else if (logicalGroup.ConstantBufferMemberStart != -1)
                {
                    break; // group is finished, no need to scan the end
                }
            }

            for (int index = 0, slot = 0; index < DescriptorSetLayoutBuilder.Entries.Count; index++)
            {
                var descriptorSetEntry = DescriptorSetLayoutBuilder.Entries[index];
                if (descriptorSetEntry.LogicalGroup == name)
                {
                    // First item?
                    if (logicalGroup.DescriptorEntryStart == -1)
                    {
                        logicalGroup.DescriptorSlotStart  = slot;
                        logicalGroup.DescriptorEntryStart = index;
                    }

                    // Update count
                    logicalGroup.DescriptorEntryCount = index + 1 - logicalGroup.DescriptorEntryStart;
                    logicalGroup.DescriptorSlotCount += descriptorSetEntry.ArraySize;

                    // Hash
                    hashBuilder.Write(descriptorSetEntry.Key.Name);
                    hashBuilder.Write(descriptorSetEntry.Class);
                    hashBuilder.Write(descriptorSetEntry.ArraySize);
                }
                else if (logicalGroup.DescriptorEntryStart != -1)
                {
                    break; // group is finished, no need to scan the end
                }

                slot += descriptorSetEntry.ArraySize;
            }

            logicalGroup.Hash = hashBuilder.ComputeHash();

            return(logicalGroup);
        }