private void RenderButtonBars(float width, BurstCompileTarget target, out bool doRefresh, out bool doCopy, out int fontIndex) { float remainingWidth = width; var contentDisasm = new GUIContent("Enhanced Disassembly"); var contentSafety = new GUIContent("Safety Checks"); var contentOptimizations = new GUIContent("Optimizations"); var contentFastMath = new GUIContent("Fast Math"); var contentCodeGenOptions = new GUIContent("Auto"); var contentLabelFontSize = new GUIContent("Font Size"); var contentFontSize = new GUIContent("99"); var contentRefresh = new GUIContent("Refresh Disassembly"); var contentCopyToClip = new GUIContent("Copy to Clipboard"); GUILayout.BeginHorizontal(); _enhancedDisassembly = GUILayout.Toggle(_enhancedDisassembly, contentDisasm, EditorStyles.toggle); FlowToNewLine(ref remainingWidth, width, EditorStyles.toggle, contentDisasm); _safetyChecks = GUILayout.Toggle(_safetyChecks, contentSafety, EditorStyles.toggle); FlowToNewLine(ref remainingWidth, width, EditorStyles.toggle, contentSafety); _optimizations = GUILayout.Toggle(_optimizations, contentOptimizations, EditorStyles.toggle); FlowToNewLine(ref remainingWidth, width, EditorStyles.toggle, contentOptimizations); _fastMath = GUILayout.Toggle(_fastMath, contentFastMath, EditorStyles.toggle); FlowToNewLine(ref remainingWidth, width, EditorStyles.toggle, contentFastMath); EditorGUI.BeginDisabledGroup(!target.IsSupported); _codeGenOptions = EditorGUILayout.Popup(_codeGenOptions, CodeGenOptions, EditorStyles.popup); FlowToNewLine(ref remainingWidth, width, EditorStyles.popup, contentCodeGenOptions); GUILayout.Label("Font Size", EditorStyles.label); fontIndex = EditorGUILayout.Popup(_fontSizeIndex, _fontSizesText, EditorStyles.popup); FlowToNewLine(ref remainingWidth, width, EditorStyles.label, contentLabelFontSize); FlowToNewLine(ref remainingWidth, width, EditorStyles.popup, contentFontSize); doRefresh = GUILayout.Button(contentRefresh, EditorStyles.miniButton); FlowToNewLine(ref remainingWidth, width, EditorStyles.miniButton, contentRefresh); doCopy = GUILayout.Button(contentCopyToClip, EditorStyles.miniButton); FlowToNewLine(ref remainingWidth, width, EditorStyles.miniButton, contentCopyToClip); EditorGUI.EndDisabledGroup(); GUILayout.EndHorizontal(); _disasmKind = (DisassemblyKind)GUILayout.Toolbar((int)_disasmKind, DisassemblyKindNames, GUILayout.Width(width)); }
private void RenderButtonBars(float width, BurstCompileTarget target, out bool doCopy, out int fontIndex) { float remainingWidth = width; var contentDisasm = new GUIContent("Enhanced Disassembly"); var contentSafety = new GUIContent("Safety Checks"); var contentCodeGenOptions = new GUIContent("Auto"); var contentLabelFontSize = new GUIContent("Font Size"); var contentFontSize = new GUIContent("99"); var contentCopyToClip = new GUIContent("Copy to Clipboard"); GUILayout.BeginHorizontal(); _assemblyKind = EditorGUILayout.Popup(_assemblyKind, AssemblyOptions, EditorStyles.popup); FlowToNewLine(ref remainingWidth, width, EditorStyles.popup, contentDisasm); _safetyChecks = GUILayout.Toggle(_safetyChecks, contentSafety, EditorStyles.toggle); FlowToNewLine(ref remainingWidth, width, EditorStyles.toggle, contentSafety); EditorGUI.BeginDisabledGroup(!target.HasRequiredBurstCompileAttributes); _targetCpu = (TargetCpu)EditorGUILayout.Popup((int)_targetCpu, TargetCpuNames, EditorStyles.popup); FlowToNewLine(ref remainingWidth, width, EditorStyles.popup, contentCodeGenOptions); GUILayout.Label("Font Size", EditorStyles.label); fontIndex = EditorGUILayout.Popup(_fontSizeIndex, _fontSizesText, EditorStyles.popup); FlowToNewLine(ref remainingWidth, width, EditorStyles.label, contentLabelFontSize); FlowToNewLine(ref remainingWidth, width, EditorStyles.popup, contentFontSize); doCopy = GUILayout.Button(contentCopyToClip, EditorStyles.miniButton); FlowToNewLine(ref remainingWidth, width, EditorStyles.miniButton, contentCopyToClip); EditorGUI.EndDisabledGroup(); GUILayout.EndHorizontal(); _disasmKind = (DisassemblyKind)GUILayout.Toolbar((int)_disasmKind, DisassemblyKindNames, GUILayout.ExpandWidth(true), GUILayout.MinWidth(5 * 10)); }
public static List <BurstCompileTarget> FindExecuteMethods(AssembliesType assemblyTypes) { var methodsToCompile = new List <BurstCompileTarget>(); var methodsToCompileSet = new HashSet <MethodInfo>(); var valueTypes = new List <TypeToVisit>(); var interfaceToProducer = new Dictionary <Type, Type>(); var assemblyList = GetAssemblyList(assemblyTypes); //Debug.Log("Filtered Assembly List: " + string.Join(", ", assemblyList.Select(assembly => assembly.GetName().Name))); // Find all ways to execute job types (via producer attributes) var typesVisited = new HashSet <string>(); var typesToVisit = new HashSet <string>(); foreach (var assembly in assemblyList) { var types = new List <Type>(); try { types.AddRange(assembly.GetTypes()); // Collect all generic type instances (excluding indirect instances) CollectGenericTypeInstances(assembly, types); } catch (Exception ex) { Debug.LogWarning("Unexpected exception while collecting types in assembly `" + assembly.FullName + "` Exception: " + ex); } for (var i = 0; i < types.Count; i++) { var t = types[i]; if (typesToVisit.Add(t.FullName)) { // Because the list of types returned by CollectGenericTypeInstances does not detect nested generic classes that are not // used explicitly, we need to create them if a declaring type is actually used // so for example if we have: // class MyClass<T> { class MyNestedClass { } } // class MyDerived : MyClass<int> { } // The CollectGenericTypeInstances will return typically the type MyClass<int>, but will not list MyClass<int>.MyNestedClass // So the following code is correcting this in order to fully query the full graph of generic instance types, including indirect types var nestedTypes = t.GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic); foreach (var nestedType in nestedTypes) { if (t.IsGenericType && !t.IsGenericTypeDefinition) { var parentGenericTypeArguments = t.GetGenericArguments(); // Only create nested types that are closed generic types (full generic instance types) // It happens if for example the parent class is `class MClass<T> { class MyNestedGeneric<T1> {} }` // In that case, MyNestedGeneric<T1> is closed in the context of MClass<int>, so we don't process them if (nestedType.GetGenericArguments().Length == parentGenericTypeArguments.Length) { var instanceNestedType = nestedType.MakeGenericType(parentGenericTypeArguments); types.Add(instanceNestedType); } } else { types.Add(nestedType); } } } } foreach (var t in types) { // If the type has been already visited, don't try to visit it if (!typesVisited.Add(t.FullName) || (t.IsGenericTypeDefinition && !t.IsInterface)) { continue; } try { // collect methods with types having a [BurstCompile] attribute bool visitStaticMethods = HasBurstCompileAttribute(t); bool isValueType = false; if (t.IsInterface) { object[] attrs = t.GetCustomAttributes(typeof(JobProducerTypeAttribute), false); if (attrs.Length == 0) { continue; } JobProducerTypeAttribute attr = (JobProducerTypeAttribute)attrs[0]; interfaceToProducer.Add(t, attr.ProducerType); //Debug.Log($"{t} has producer {attr.ProducerType}"); } else if (t.IsValueType) { // NOTE: Make sure that we don't use a value type generic definition (e.g `class Outer<T> { struct Inner { } }`) // We are only working on plain type or generic type instance! if (!t.IsGenericTypeDefinition) { isValueType = true; } } if (isValueType || visitStaticMethods) { valueTypes.Add(new TypeToVisit(t, visitStaticMethods)); } } catch (Exception ex) { Debug.LogWarning("Unexpected exception while inspecting type `" + t + "` IsConstructedGenericType: " + t.IsConstructedGenericType + " IsGenericTypeDef: " + t.IsGenericTypeDefinition + " IsGenericParam: " + t.IsGenericParameter + " Exception: " + ex); } } } //Debug.Log($"Mapped {interfaceToProducer.Count} producers; {valueTypes.Count} value types"); // Revisit all types to find things that are compilable using the above producers. foreach (var typePair in valueTypes) { var type = typePair.Type; // collect static [BurstCompile] methods if (typePair.CollectStaticMethods) { try { var methods = type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); foreach (var method in methods) { if (HasBurstCompileAttribute(method)) { var target = new BurstCompileTarget(method, type, null, true); methodsToCompile.Add(target); } } } catch (Exception ex) { Debug.LogException(ex); } } // If the type is not a value type, we don't need to proceed with struct Jobs if (!type.IsValueType) { continue; } // Otherwise try to find if we have an interface producer setup on the class foreach (var interfaceType in type.GetInterfaces()) { var genericLessInterface = interfaceType; if (interfaceType.IsGenericType) { genericLessInterface = interfaceType.GetGenericTypeDefinition(); } Type foundProducer; if (interfaceToProducer.TryGetValue(genericLessInterface, out foundProducer)) { var genericParams = new List <Type> { type }; if (interfaceType.IsGenericType) { genericParams.AddRange(interfaceType.GenericTypeArguments); } try { var executeType = foundProducer.MakeGenericType(genericParams.ToArray()); var executeMethod = executeType.GetMethod("Execute"); if (executeMethod == null) { throw new InvalidOperationException($"Burst reflection error. The type `{executeType}` does not contain an `Execute` method"); } // We will not try to record more than once a method in the methods to compile // This can happen if a job interface is inheriting from another job interface which are using in the end the same // job producer type if (methodsToCompileSet.Add(executeMethod)) { var target = new BurstCompileTarget(executeMethod, type, interfaceType, false); methodsToCompile.Add(target); } } catch (Exception ex) { Debug.LogException(ex); } } } } return(methodsToCompile); }