# CreateDetailsViewController()

> Creates a View Controller object that draws the Profiler module’s Details View in the Profiler window. Unity calls this method automatically when the module is selected in the Profiler window.

## Definition

* **Type:** Method
* **Namespace:** [Unity.Profiling.Editor](/engine/6000.5/script-reference/unity/profiling/editor.md)
* **Assembly:** UnityEditor.CoreModule

```csharp
public virtual ProfilerModuleViewController CreateDetailsViewController()
```

### Returns

| Type                                                                                                                   | Description                                                                                                                                                                                                                                                                                                                                                   |
| ---------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [ProfilerModuleViewController](/engine/6000.5/script-reference/unity/profiling/editor/profilermoduleviewcontroller.md) | Returns a [ProfilerModuleViewController](/engine/6000.5/script-reference/unity/profiling/editor/profilermoduleviewcontroller.md) derived object that draws the module’s Details View in the Profiler window. The default value is a view controller that displays a list of the module’s chart counters alongside their current values in the selected frame. |

### Remarks

To present a bespoke visualization of your performance data when your module is selected, override this method. To do this, define a new [ProfilerModuleViewController](/engine/6000.5/script-reference/unity/profiling/editor/profilermoduleviewcontroller.md) derived type, where the custom drawing can be implemented, and return a new instance of it in this method.

![ProfilerModuleCustomDetailsView (CreateDetailsViewController())](/api/media?file=/engine/6000.5/media/images/ProfilerModuleCustomDetailsView.png).

```csharp
using System;
using Unity.Profiling;
using Unity.Profiling.Editor;
using UnityEditor;
using UnityEngine.UIElements;

//--Module--

[Serializable]
[ProfilerModuleMetadata("Garbage Collection")]
public class GarbageCollectionProfilerModule : ProfilerModule
{
    static readonly ProfilerCounterDescriptor[] k_ChartCounters = new ProfilerCounterDescriptor[]
    {
        new ProfilerCounterDescriptor("GC Reserved Memory", ProfilerCategory.Memory),
        new ProfilerCounterDescriptor("GC Used Memory", ProfilerCategory.Memory),
        new ProfilerCounterDescriptor("GC Allocated In Frame", ProfilerCategory.Memory),
    };

    // Specify a list of Profiler category names, which should be auto-enabled when the module is active.
    static readonly string[] k_AutoEnabledCategoryNames = new string[]
    {
        ProfilerCategory.Memory.Name,
    };

    public GarbageCollectionProfilerModule() : base(k_ChartCounters, autoEnabledCategoryNames: k_AutoEnabledCategoryNames) { }

    public override ProfilerModuleViewController CreateDetailsViewController()
    {
        return new GarbageCollectionDetailsViewController(ProfilerWindow);
    }
}

//--Module Custom Drawing--

public class GarbageCollectionDetailsViewController : ProfilerModuleViewController
{
    const string k_UxmlResourceName = "Assets/Editor/GarbageCollectionDetailsView.uxml";
    const string k_UxmlElementId_GarbageCollectionDetailsView<b>BarFill = "garbage-collection-details-view</b>bar-fill";
    const string k_UxmlElementId_GarbageCollectionDetailsView<b>BarLabel = "garbage-collection-details-view</b>bar-label";

    static readonly ProfilerCounterDescriptor k_GcReservedMemoryCounterDescriptor = new ProfilerCounterDescriptor("GC Reserved Memory", ProfilerCategory.Memory);
    static readonly ProfilerCounterDescriptor k_GcUsedMemoryCounterDescriptor = new ProfilerCounterDescriptor("GC Used Memory", ProfilerCategory.Memory);

    VisualElement m_BarFill;
    Label m_BarLabel;

    public GarbageCollectionDetailsViewController(ProfilerWindow profilerWindow) : base(profilerWindow) { }

    protected override VisualElement CreateView()
    {
        var template = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(k_UxmlResourceName);
        var view = template.Instantiate();

        m_BarFill = view.Q<VisualElement>(name: k_UxmlElementId_GarbageCollectionDetailsView__BarFill);
        m_BarLabel = view.Q<Label>(name: k_UxmlElementId_GarbageCollectionDetailsView__BarLabel);

        ReloadData(ProfilerWindow.selectedFrameIndex);
        ProfilerWindow.SelectedFrameIndexChanged += OnSelectedFrameIndexChanged;

        return view;
    }

    protected override void Dispose(bool disposing)
    {
        if (!disposing)
            return;

        ProfilerWindow.SelectedFrameIndexChanged -= OnSelectedFrameIndexChanged;
        base.Dispose(disposing);
    }

    void OnSelectedFrameIndexChanged(long selectedFrameIndex)
    {
        ReloadData(selectedFrameIndex);
    }

    void ReloadData(long selectedFrameIndex)
    {
        long gcReservedBytes = 0;
        long gcUsedBytes = 0;

        var selectedFrameIndexInt32 = Convert.ToInt32(selectedFrameIndex);
        using (var frameData = UnityEditorInternal.ProfilerDriver.GetRawFrameDataView(selectedFrameIndexInt32, 0))
        {
            if (frameData == null || !frameData.valid)
                return;

            var gcReservedBytesMarkerId = frameData.GetMarkerId(k_GcReservedMemoryCounterDescriptor.Name);
            gcReservedBytes = frameData.GetCounterValueAsLong(gcReservedBytesMarkerId);

            var gcUsedBytesMarkerId = frameData.GetMarkerId(k_GcUsedMemoryCounterDescriptor.Name);
            gcUsedBytes = frameData.GetCounterValueAsLong(gcUsedBytesMarkerId);
        }

        float gcUsedBytesScalar = (float)gcUsedBytes / gcReservedBytes;
        m_BarFill.style.width = new Length(gcUsedBytesScalar * 100, LengthUnit.Percent);
        m_BarLabel.text = $"{EditorUtility.FormatBytes(gcUsedBytes)} / {EditorUtility.FormatBytes(gcReservedBytes)}";
    }
}

//--Assets/Editor/GarbageCollectionDetailsView.uxml--

<?xml version="1.0" encoding="utf-8"?>
<engine:UXML
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:engine="UnityEngine.UIElements"
    xmlns:editor="UnityEditor.UIElements"
    xsi:noNamespaceSchemaLocation="../../UIElementsSchema/UIElements.xsd">
  <engine:Style src="GarbageCollectionDetailsView.uss"/>
  <engine:VisualElement name="garbage-collection-details-view">
    <engine:Label name="garbage-collection-details-view__title-label" text="Garbage Collection"/>
    <engine:VisualElement name="garbage-collection-details-view__bar">
      <engine:VisualElement name="garbage-collection-details-view__bar-fill"/>
    </engine:VisualElement>
    <engine:Label name="garbage-collection-details-view__bar-label"/>
  </engine:VisualElement>
</engine:UXML>

//--Assets/Editor/GarbageCollectionDetailsView.uss--

#garbage-collection-details-view
{
    flex-grow: 1;
    margin: 8px;
}

#garbage-collection-details-view__title-label
{
    -unity-font-style: bold;
    margin-bottom: 8px;
}

#garbage-collection-details-view__bar
{
    background-color: gray;
    flex-direction: row;
    height: 20px;
}

#garbage-collection-details-view__bar-fill
{
    background-color: #B2194C;
    position: absolute;
    height: 100%;
}
```

Additional Resources: [ProfilerModuleViewController](/engine/6000.5/script-reference/unity/profiling/editor/profilermoduleviewcontroller.md).
