Merge branch '1.5' into dotnet7

This commit is contained in:
Wojciech Figat
2022-12-21 10:35:58 +01:00
330 changed files with 3405 additions and 1555 deletions

BIN
Content/Editor/Camera/M_Camera.flax (Stored with Git LFS)

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
Content/Editor/DefaultFontMaterial.flax (Stored with Git LFS)

Binary file not shown.

Binary file not shown.

BIN
Content/Editor/Gizmo/Material.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Editor/Gizmo/MaterialWire.flax (Stored with Git LFS)

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
Content/Editor/Highlight Material.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Editor/Icons/IconsMaterial.flax (Stored with Git LFS)

Binary file not shown.

Binary file not shown.

View File

@@ -2,6 +2,7 @@
// Version: @0 // Version: @0
#define MATERIAL 1 #define MATERIAL 1
#define USE_PER_VIEW_CONSTANTS 1
@3 @3
#include "./Flax/Common.hlsl" #include "./Flax/Common.hlsl"
@@ -10,17 +11,9 @@
@7 @7
// Primary constant buffer (with additional material parameters) // Primary constant buffer (with additional material parameters)
META_CB_BEGIN(0, Data) META_CB_BEGIN(0, Data)
float4x4 ViewProjectionMatrix;
float4x4 WorldMatrix; float4x4 WorldMatrix;
float4x4 ViewMatrix;
float4x4 InvWorld; float4x4 InvWorld;
float4x4 SVPositionToWorld; float4x4 SVPositionToWorld;
float3 ViewPos;
float ViewFar;
float3 ViewDir;
float TimeParam;
float4 ViewInfo;
float4 ScreenSize;
@1META_CB_END @1META_CB_END
// Use depth buffer for per-pixel decal layering // Use depth buffer for per-pixel decal layering

View File

@@ -2,6 +2,7 @@
// Version: @0 // Version: @0
#define MATERIAL 1 #define MATERIAL 1
#define USE_PER_VIEW_CONSTANTS 1
@3 @3
#include "./Flax/Common.hlsl" #include "./Flax/Common.hlsl"
#include "./Flax/MaterialCommon.hlsl" #include "./Flax/MaterialCommon.hlsl"
@@ -9,23 +10,14 @@
@7 @7
// Primary constant buffer (with additional material parameters) // Primary constant buffer (with additional material parameters)
META_CB_BEGIN(0, Data) META_CB_BEGIN(0, Data)
float4x4 ViewProjectionMatrix;
float4x4 WorldMatrix; float4x4 WorldMatrix;
float4x4 LocalMatrix; float4x4 LocalMatrix;
float4x4 ViewMatrix;
float3 ViewPos;
float ViewFar;
float3 ViewDir;
float TimeParam;
float4 ViewInfo;
float4 ScreenSize;
float3 Dummy0; float3 Dummy0;
float WorldDeterminantSign; float WorldDeterminantSign;
float MeshMinZ; float MeshMinZ;
float Segment; float Segment;
float ChunksPerSegment; float ChunksPerSegment;
float PerInstanceRandom; float PerInstanceRandom;
float4 TemporalAAJitter;
float3 GeometrySize; float3 GeometrySize;
float MeshMaxZ; float MeshMaxZ;
@1META_CB_END @1META_CB_END

View File

@@ -2,6 +2,7 @@
// Version: @0 // Version: @0
#define MATERIAL 1 #define MATERIAL 1
#define USE_PER_VIEW_CONSTANTS 1
@3 @3
// Ribbons don't use sorted indices so overlap the segment distances buffer on the slot // Ribbons don't use sorted indices so overlap the segment distances buffer on the slot
#define HAS_SORTED_INDICES (!defined(_VS_Ribbon)) #define HAS_SORTED_INDICES (!defined(_VS_Ribbon))
@@ -19,15 +20,7 @@ struct SpriteInput
// Primary constant buffer (with additional material parameters) // Primary constant buffer (with additional material parameters)
META_CB_BEGIN(0, Data) META_CB_BEGIN(0, Data)
float4x4 ViewProjectionMatrix;
float4x4 WorldMatrix; float4x4 WorldMatrix;
float4x4 ViewMatrix;
float3 ViewPos;
float ViewFar;
float3 ViewDir;
float TimeParam;
float4 ViewInfo;
float4 ScreenSize;
uint SortedIndicesOffset; uint SortedIndicesOffset;
float PerInstanceRandom; float PerInstanceRandom;
int ParticleStride; int ParticleStride;

View File

@@ -2,6 +2,7 @@
// Version: @0 // Version: @0
#define MATERIAL 1 #define MATERIAL 1
#define USE_PER_VIEW_CONSTANTS 1
@3 @3
#include "./Flax/Common.hlsl" #include "./Flax/Common.hlsl"
#include "./Flax/MaterialCommon.hlsl" #include "./Flax/MaterialCommon.hlsl"
@@ -9,23 +10,11 @@
@7 @7
// Primary constant buffer (with additional material parameters) // Primary constant buffer (with additional material parameters)
META_CB_BEGIN(0, Data) META_CB_BEGIN(0, Data)
float4x4 ViewProjectionMatrix;
float4x4 WorldMatrix; float4x4 WorldMatrix;
float4x4 ViewMatrix;
float4x4 PrevViewProjectionMatrix;
float4x4 PrevWorldMatrix; float4x4 PrevWorldMatrix;
float4x4 MainViewProjectionMatrix;
float4 MainScreenSize;
float3 ViewPos;
float ViewFar;
float3 ViewDir;
float TimeParam;
float4 ViewInfo;
float4 ScreenSize;
float2 Dummy0; float2 Dummy0;
float LODDitherFactor; float LODDitherFactor;
float PerInstanceRandom; float PerInstanceRandom;
float4 TemporalAAJitter;
float3 GeometrySize; float3 GeometrySize;
float WorldDeterminantSign; float WorldDeterminantSign;
@1META_CB_END @1META_CB_END

View File

@@ -2,6 +2,7 @@
// Version: @0 // Version: @0
#define MATERIAL 1 #define MATERIAL 1
#define USE_PER_VIEW_CONSTANTS 1
@3 @3
// Enables/disables smooth terrain chunks LOD transitions (with morphing higher LOD near edges to the lower LOD in the neighbour) // Enables/disables smooth terrain chunks LOD transitions (with morphing higher LOD near edges to the lower LOD in the neighbour)
#define USE_SMOOTH_LOD_TRANSITION 1 #define USE_SMOOTH_LOD_TRANSITION 1
@@ -16,15 +17,7 @@
@7 @7
// Primary constant buffer (with additional material parameters) // Primary constant buffer (with additional material parameters)
META_CB_BEGIN(0, Data) META_CB_BEGIN(0, Data)
float4x4 ViewProjectionMatrix;
float4x4 WorldMatrix; float4x4 WorldMatrix;
float4x4 ViewMatrix;
float3 ViewPos;
float ViewFar;
float3 ViewDir;
float TimeParam;
float4 ViewInfo;
float4 ScreenSize;
float3 WorldInvScale; float3 WorldInvScale;
float WorldDeterminantSign; float WorldDeterminantSign;
float PerInstanceRandom; float PerInstanceRandom;

View File

@@ -2,6 +2,7 @@
// Version: @0 // Version: @0
#define MATERIAL 1 #define MATERIAL 1
#define USE_PER_VIEW_CONSTANTS 1
@3 @3
#include "./Flax/Common.hlsl" #include "./Flax/Common.hlsl"
@@ -11,17 +12,9 @@
// Primary constant buffer (with additional material parameters) // Primary constant buffer (with additional material parameters)
META_CB_BEGIN(0, Data) META_CB_BEGIN(0, Data)
float4x4 ViewProjectionMatrix;
float4x4 InverseViewProjectionMatrix; float4x4 InverseViewProjectionMatrix;
float4x4 ViewMatrix;
float4x4 WorldMatrix; float4x4 WorldMatrix;
float4x4 WorldMatrixInverseTransposed; float4x4 WorldMatrixInverseTransposed;
float3 ViewPos;
float ViewFar;
float3 ViewDir;
float TimeParam;
float4 ViewInfo;
float4 ScreenSize;
float3 GridSize; float3 GridSize;
float PerInstanceRandom; float PerInstanceRandom;
float Dummy0; float Dummy0;

Binary file not shown.

Binary file not shown.

BIN
Content/Editor/SpriteMaterial.flax (Stored with Git LFS)

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
Content/Editor/TexturePreviewMaterial.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Editor/Wires Debug Material.flax (Stored with Git LFS)

Binary file not shown.

Binary file not shown.

BIN
Content/Engine/DefaultMaterial.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Engine/DefaultTerrainMaterial.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Engine/SingleColorMaterial.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Engine/SkyboxMaterial.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Shaders/GI/DDGI.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Shaders/GI/GlobalSurfaceAtlas.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Shaders/TAA.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Shaders/VolumetricFog.flax (Stored with Git LFS)

Binary file not shown.

View File

@@ -7,6 +7,7 @@
#include "Engine/Core/Log.h" #include "Engine/Core/Log.h"
#include "Engine/Core/Math/Vector2.h" #include "Engine/Core/Math/Vector2.h"
#include "Engine/Core/Types/DateTime.h" #include "Engine/Core/Types/DateTime.h"
#include "Engine/Core/Types/TimeSpan.h"
#include "Editor/Editor.h" #include "Editor/Editor.h"
#include "Editor/ProjectInfo.h" #include "Editor/ProjectInfo.h"
#include "Engine/Engine/EngineService.h" #include "Engine/Engine/EngineService.h"

View File

@@ -497,6 +497,8 @@ bool UWPPlatformTools::OnPerformAOT(CookingData& data, AotConfig& config, const
bool UWPPlatformTools::OnPostProcess(CookingData& data) bool UWPPlatformTools::OnPostProcess(CookingData& data)
{ {
LOG(Error, "UWP (Windows Store) platform has been deprecated and soon will be removed!");
// Special case for UWP // Special case for UWP
// FlaxEngine.dll cannot be added to the solution as `Content` item (due to conflicts with C++ /CX FlaxEngine.dll) // FlaxEngine.dll cannot be added to the solution as `Content` item (due to conflicts with C++ /CX FlaxEngine.dll)
// Use special directory for it (generated UWP project handles this case and copies lib to the output) // Use special directory for it (generated UWP project handles this case and copies lib to the output)

View File

@@ -115,6 +115,8 @@ bool DeployDataStep::Perform(CookingData& data)
auto& buildSettings = *BuildSettings::Get(); auto& buildSettings = *BuildSettings::Get();
for (auto& e : buildSettings.AdditionalAssets) for (auto& e : buildSettings.AdditionalAssets)
data.AddRootAsset(e.GetID()); data.AddRootAsset(e.GetID());
for (auto& e : buildSettings.AdditionalScenes)
data.AddRootAsset(e.ID);
Array<String> files; Array<String> files;
for (auto& e : buildSettings.AdditionalAssetFolders) for (auto& e : buildSettings.AdditionalAssetFolders)
{ {

View File

@@ -225,7 +225,8 @@ namespace FlaxEditor.CustomEditors.Editors
} }
private static HashSet<PropertiesList> _visibleIfPropertiesListsCache; private static HashSet<PropertiesList> _visibleIfPropertiesListsCache;
private static Dictionary<string, GroupElement> _groups; private static Stack<Dictionary<string, GroupElement>> _groups;
private static List<Dictionary<string, GroupElement>> _groupsPool;
private VisibleIfCache[] _visibleIfCaches; private VisibleIfCache[] _visibleIfCaches;
private bool _isNull; private bool _isNull;
@@ -514,17 +515,38 @@ namespace FlaxEditor.CustomEditors.Editors
menu.Show(groupPanel, location); menu.Show(groupPanel, location);
} }
internal static void OnGroupUsage() internal static void OnGroupsBegin()
{ {
if (_groups != null) if (_groups == null)
_groups.Clear(); _groups = new Stack<Dictionary<string, GroupElement>>();
if (_groupsPool == null)
_groupsPool = new List<Dictionary<string, GroupElement>>();
Dictionary<string, GroupElement> group;
if (_groupsPool.Count != 0)
{
group = _groupsPool[0];
_groupsPool.RemoveAt(0);
}
else
{
group = new Dictionary<string, GroupElement>();
}
_groups.Push(group);
}
internal static void OnGroupsEnd()
{
var groups = _groups.Pop();
groups.Clear();
_groupsPool.Add(groups);
} }
internal static LayoutElementsContainer OnGroup(LayoutElementsContainer layout, EditorDisplayAttribute display) internal static LayoutElementsContainer OnGroup(LayoutElementsContainer layout, EditorDisplayAttribute display)
{ {
if (display?.Group != null) if (display?.Group != null)
{ {
if (_groups != null && _groups.TryGetValue(display.Group, out var group)) var groups = _groups.Peek();
if (groups.TryGetValue(display.Group, out var group))
{ {
// Reuse group // Reuse group
layout = group; layout = group;
@@ -532,12 +554,10 @@ namespace FlaxEditor.CustomEditors.Editors
else else
{ {
// Add new group // Add new group
if (_groups == null)
_groups = new Dictionary<string, GroupElement>();
group = layout.Group(display.Group); group = layout.Group(display.Group);
group.Panel.Tag = group; group.Panel.Tag = group;
group.Panel.MouseButtonRightClicked += OnGroupPanelMouseButtonRightClicked; group.Panel.MouseButtonRightClicked += OnGroupPanelMouseButtonRightClicked;
_groups.Add(display.Group, group); groups.Add(display.Group, group);
layout = group; layout = group;
} }
} }
@@ -713,7 +733,7 @@ namespace FlaxEditor.CustomEditors.Editors
items.Sort(); items.Sort();
// Add items // Add items
OnGroupUsage(); OnGroupsBegin();
for (int i = 0; i < items.Count; i++) for (int i = 0; i < items.Count; i++)
{ {
var item = items[i]; var item = items[i];
@@ -759,7 +779,7 @@ namespace FlaxEditor.CustomEditors.Editors
} while (c != null); } while (c != null);
} }
} }
OnGroupUsage(); OnGroupsEnd();
} }
/// <inheritdoc /> /// <inheritdoc />

View File

@@ -37,6 +37,16 @@ namespace FlaxEditor.GUI.Docking
// Focus window // Focus window
window.Focus(); window.Focus();
// Check if window is maximized and restore window.
if (window.IsMaximized)
{
// Restore window and set position to mouse.
var mousePos = window.MousePosition;
var previousSize = window.Size;
window.Restore();
window.Position = FlaxEngine.Input.MouseScreenPosition - mousePos * window.Size / previousSize;
}
// Calculate dragging offset and move window to the destination position // Calculate dragging offset and move window to the destination position
var mouseScreenPosition = FlaxEngine.Input.MouseScreenPosition; var mouseScreenPosition = FlaxEngine.Input.MouseScreenPosition;

View File

@@ -51,10 +51,6 @@ namespace FlaxEditor.GUI.Docking
if (_window == null) if (_window == null)
return; return;
// Check if window is maximized
if (_window.IsMaximized)
return;
// Create docking hint window // Create docking hint window
DockHintWindow.Create(this); DockHintWindow.Create(this);
} }

View File

@@ -81,6 +81,20 @@ namespace FlaxEditor.GUI
private bool IsInputValid => !string.IsNullOrWhiteSpace(_inputField.Text) && (_inputField.Text == _startValue || Validate == null || Validate(this, _inputField.Text)); private bool IsInputValid => !string.IsNullOrWhiteSpace(_inputField.Text) && (_inputField.Text == _startValue || Validate == null || Validate(this, _inputField.Text));
/// <inheritdoc />
public override void Update(float deltaTime)
{
var mouseLocation = Root.MousePosition;
if (!ContainsPoint(ref mouseLocation) && RootWindow.ContainsFocus && Text != _startValue)
{
// rename item before closing if left mouse button in clicked
if (FlaxEngine.Input.GetMouseButtonDown(MouseButton.Left))
OnEnd();
}
base.Update(deltaTime);
}
private void OnTextChanged() private void OnTextChanged()
{ {
if (Validate == null) if (Validate == null)

View File

@@ -1,5 +1,6 @@
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved. // Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
using System;
using FlaxEngine; using FlaxEngine;
using FlaxEngine.GUI; using FlaxEngine.GUI;
@@ -192,4 +193,92 @@ namespace FlaxEditor.GUI
} }
} }
} }
/// <summary>
/// The table row that contains events for mouse interaction.
/// </summary>
[HideInEditor]
public class ClickableRow : Row
{
private bool _leftClick;
private bool _isRightDown;
/// <summary>
/// The double click event.
/// </summary>
public Action DoubleClick;
/// <summary>
/// The left mouse button click event.
/// </summary>
public Action LeftClick;
/// <summary>
/// The right mouse button click event.
/// </summary>
public Action RightClick;
/// <summary>
/// The double click event.
/// </summary>
public Action<ClickableRow> RowDoubleClick;
/// <summary>
/// The left mouse button click event.
/// </summary>
public Action<ClickableRow> RowLeftClick;
/// <summary>
/// The right mouse button click event.
/// </summary>
public Action<ClickableRow> RowRightClick;
/// <inheritdoc />
public override bool OnMouseDoubleClick(Float2 location, MouseButton button)
{
DoubleClick?.Invoke();
RowDoubleClick?.Invoke(this);
return base.OnMouseDoubleClick(location, button);
}
/// <inheritdoc />
public override bool OnMouseDown(Float2 location, MouseButton button)
{
if (button == MouseButton.Left)
_leftClick = true;
else if (button == MouseButton.Right)
_isRightDown = true;
return base.OnMouseDown(location, button);
}
/// <inheritdoc />
public override bool OnMouseUp(Float2 location, MouseButton button)
{
if (button == MouseButton.Left && _leftClick)
{
_leftClick = false;
LeftClick?.Invoke();
RowLeftClick?.Invoke(this);
}
else if (button == MouseButton.Right && _isRightDown)
{
_isRightDown = false;
RightClick?.Invoke();
RowRightClick?.Invoke(this);
}
return base.OnMouseUp(location, button);
}
/// <inheritdoc />
public override void OnMouseLeave()
{
_leftClick = false;
_isRightDown = false;
base.OnMouseLeave();
}
}
} }

View File

@@ -25,7 +25,7 @@ namespace FlaxEditor.SceneGraph.Actors
{ {
base.OnContextMenu(contextMenu); base.OnContextMenu(contextMenu);
contextMenu.AddButton("Add mesh collider", OnAddMeshCollider).Enabled = ((StaticModel)Actor).Model != null; contextMenu.AddButton("Add collider", OnAddMeshCollider).Enabled = ((StaticModel)Actor).Model != null;
} }
private void OnAddMeshCollider() private void OnAddMeshCollider()
@@ -33,6 +33,56 @@ namespace FlaxEditor.SceneGraph.Actors
var model = ((StaticModel)Actor).Model; var model = ((StaticModel)Actor).Model;
if (!model) if (!model)
return; return;
// Special case for in-built Editor models that can use analytical collision
var modelPath = model.Path;
if (modelPath.EndsWith("/Primitives/Cube.flax", StringComparison.Ordinal))
{
var actor = new BoxCollider
{
StaticFlags = Actor.StaticFlags,
Transform = Actor.Transform,
};
Editor.Instance.SceneEditing.Spawn(actor, Actor);
return;
}
if (modelPath.EndsWith("/Primitives/Sphere.flax", StringComparison.Ordinal))
{
var actor = new SphereCollider
{
StaticFlags = Actor.StaticFlags,
Transform = Actor.Transform,
};
Editor.Instance.SceneEditing.Spawn(actor, Actor);
return;
}
if (modelPath.EndsWith("/Primitives/Plane.flax", StringComparison.Ordinal))
{
var actor = new BoxCollider
{
StaticFlags = Actor.StaticFlags,
Transform = Actor.Transform,
Size = new Float3(100.0f, 100.0f, 1.0f),
};
Editor.Instance.SceneEditing.Spawn(actor, Actor);
return;
}
if (modelPath.EndsWith("/Primitives/Capsule.flax", StringComparison.Ordinal))
{
var actor = new CapsuleCollider
{
StaticFlags = Actor.StaticFlags,
Transform = Actor.Transform,
Radius = 25.0f,
Height = 50.0f,
};
Editor.Instance.SceneEditing.Spawn(actor, Actor);
actor.LocalPosition = new Vector3(0, 50.0f, 0);
actor.LocalOrientation = Quaternion.Euler(0, 0, 90.0f);
return;
}
// Create collision data (or reuse) and add collision actor
Action<CollisionData> created = collisionData => Action<CollisionData> created = collisionData =>
{ {
var actor = new MeshCollider var actor = new MeshCollider

View File

@@ -148,7 +148,16 @@ namespace FlaxEditor.Surface
public void GetConnectionColor(ScriptType type, ConnectionsHint hint, out Color color) public void GetConnectionColor(ScriptType type, ConnectionsHint hint, out Color color)
{ {
if (type == ScriptType.Null) if (type == ScriptType.Null)
color = Colors.Default; {
if (hint == ConnectionsHint.Vector)
color = Colors.Vector;
else if (hint == ConnectionsHint.Scalar)
color = Colors.Float;
else if (hint == ConnectionsHint.Enum)
color = Colors.Enum;
else
color = Colors.Default;
}
else if (type.IsPointer || type.IsReference) else if (type.IsPointer || type.IsReference)
{ {
// Find underlying type without `*` or `&` // Find underlying type without `*` or `&`

View File

@@ -286,7 +286,7 @@ namespace FlaxEditor.Surface
internal static void DisplayGraphParameters(LayoutElementsContainer layout, GraphParameterData[] data, GetGraphParameterDelegate getter, SetGraphParameterDelegate setter, ValueContainer values, GetGraphParameterDelegate defaultValueGetter = null, CustomPropertySpawnDelegate propertySpawn = null) internal static void DisplayGraphParameters(LayoutElementsContainer layout, GraphParameterData[] data, GetGraphParameterDelegate getter, SetGraphParameterDelegate setter, ValueContainer values, GetGraphParameterDelegate defaultValueGetter = null, CustomPropertySpawnDelegate propertySpawn = null)
{ {
CustomEditors.Editors.GenericEditor.OnGroupUsage(); CustomEditors.Editors.GenericEditor.OnGroupsBegin();
for (int i = 0; i < data.Length; i++) for (int i = 0; i < data.Length; i++)
{ {
ref var e = ref data[i]; ref var e = ref data[i];
@@ -333,7 +333,7 @@ namespace FlaxEditor.Surface
else else
propertySpawn(itemLayout, valueContainer, ref e); propertySpawn(itemLayout, valueContainer, ref e);
} }
CustomEditors.Editors.GenericEditor.OnGroupUsage(); CustomEditors.Editors.GenericEditor.OnGroupsEnd();
} }
internal static string GetMethodDisplayName(string methodName) internal static string GetMethodDisplayName(string methodName)

View File

@@ -372,7 +372,7 @@ namespace FlaxEditor.Surface
return; return;
} }
var parameters = window.VisjectSurface.Parameters; var parameters = window.VisjectSurface.Parameters;
CustomEditors.Editors.GenericEditor.OnGroupUsage(); CustomEditors.Editors.GenericEditor.OnGroupsBegin();
for (int i = 0; i < parameters.Count; i++) for (int i = 0; i < parameters.Count; i++)
{ {
var p = parameters[i]; var p = parameters[i];
@@ -429,7 +429,7 @@ namespace FlaxEditor.Surface
var property = itemLayout.AddPropertyItem(propertyLabel, tooltipText); var property = itemLayout.AddPropertyItem(propertyLabel, tooltipText);
property.Property("Value", propertyValue); property.Property("Value", propertyValue);
} }
CustomEditors.Editors.GenericEditor.OnGroupUsage(); CustomEditors.Editors.GenericEditor.OnGroupsEnd();
// Parameters creating // Parameters creating
var newParameterTypes = window.NewParameterTypes; var newParameterTypes = window.NewParameterTypes;

View File

@@ -131,7 +131,7 @@ namespace FlaxEditor.Windows
ScrollBars = ScrollBars.Both, ScrollBars = ScrollBars.Both,
Parent = _split.Panel1, Parent = _split.Panel1,
}; };
// Content structure tree // Content structure tree
_tree = new Tree(false) _tree = new Tree(false)
{ {
@@ -179,7 +179,7 @@ namespace FlaxEditor.Windows
ScrollBars = ScrollBars.Vertical, ScrollBars = ScrollBars.Vertical,
Parent = _split.Panel2, Parent = _split.Panel2,
}; };
// Content View // Content View
_view = new ContentView _view = new ContentView
{ {
@@ -895,6 +895,18 @@ namespace FlaxEditor.Windows
} }
} }
/// <inheritdoc />
public override bool OnMouseDown(Float2 location, MouseButton button)
{
// Navigate through directories using the side mouse buttons
if (button == MouseButton.Extended1)
NavigateBackward();
else if (button == MouseButton.Extended2)
NavigateForward();
return base.OnMouseDown(location, button);
}
/// <inheritdoc /> /// <inheritdoc />
public override bool OnMouseUp(Float2 location, MouseButton button) public override bool OnMouseUp(Float2 location, MouseButton button)
{ {

View File

@@ -257,6 +257,7 @@ namespace FlaxEditor.Windows
break; break;
case PlatformType.UWP: case PlatformType.UWP:
name = "Windows Store"; name = "Windows Store";
layout.Label("UWP (Windows Store) platform has been deprecated and soon will be removed!", TextAlignment.Center).Label.TextColor = Color.Red;
break; break;
case PlatformType.Linux: case PlatformType.Linux:
name = "Linux"; name = "Linux";

View File

@@ -113,6 +113,17 @@ namespace FlaxEditor.Windows
set => MainRenderTask.Instance.RenderingPercentage = value; set => MainRenderTask.Instance.RenderingPercentage = value;
} }
[NoSerialize, DefaultValue(RenderingUpscaleLocation.AfterAntiAliasingPass), VisibleIf(nameof(UpscaleLocation_Visible))]
[EditorOrder(1401), EditorDisplay("Quality")]
[Tooltip("The image resolution upscale location within rendering pipeline.")]
public RenderingUpscaleLocation UpscaleLocation
{
get => MainRenderTask.Instance.UpscaleLocation;
set => MainRenderTask.Instance.UpscaleLocation = value;
}
private bool UpscaleLocation_Visible => MainRenderTask.Instance.RenderingPercentage < 1.0f;
[NoSerialize, DefaultValue(1.0f), Limit(0, 1)] [NoSerialize, DefaultValue(1.0f), Limit(0, 1)]
[EditorOrder(1500), EditorDisplay("Quality"), Tooltip("The global density scale for all foliage instances. The default value is 1. Use values from range 0-1. Lower values decrease amount of foliage instances in-game. Use it to tweak game performance for slower devices.")] [EditorOrder(1500), EditorDisplay("Quality"), Tooltip("The global density scale for all foliage instances. The default value is 1. Use values from range 0-1. Lower values decrease amount of foliage instances in-game. Use it to tweak game performance for slower devices.")]
public float FoliageDensityScale public float FoliageDensityScale

View File

@@ -0,0 +1,293 @@
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
using System;
using System.Collections.Generic;
using System.Text;
using FlaxEditor.GUI;
using FlaxEngine;
using FlaxEngine.Json;
using FlaxEngine.GUI;
using FlaxEditor.GUI.ContextMenu;
namespace FlaxEditor.Windows.Profiler
{
/// <summary>
/// The Assets profiling mode.
/// </summary>
/// <seealso cref="FlaxEditor.Windows.Profiler.ProfilerMode" />
internal sealed class Assets : ProfilerMode
{
private struct Resource
{
public string Name;
public string TypeName;
public int ReferencesCount;
public ulong MemoryUsage;
public Guid AssetId;
}
private readonly SingleChart _memoryUsageChart;
private readonly Table _table;
private SamplesBuffer<Resource[]> _resources;
private List<ClickableRow> _tableRowsCache;
private Dictionary<Guid, Resource> _resourceCache;
private StringBuilder _stringBuilder;
public Assets()
: base("Assets")
{
// Layout
var panel = new Panel(ScrollBars.Vertical)
{
AnchorPreset = AnchorPresets.StretchAll,
Offsets = Margin.Zero,
Parent = this,
};
var layout = new VerticalPanel
{
AnchorPreset = AnchorPresets.HorizontalStretchTop,
Offsets = Margin.Zero,
IsScrollable = true,
Parent = panel,
};
// Chart
_memoryUsageChart = new SingleChart
{
Title = "Assets Memory Usage (CPU)",
FormatSample = v => Utilities.Utils.FormatBytesCount((int)v),
Parent = layout,
};
_memoryUsageChart.SelectedSampleChanged += OnSelectedSampleChanged;
// Table
var headerColor = Style.Current.LightBackground;
_table = new Table
{
Columns = new[]
{
new ColumnDefinition
{
UseExpandCollapseMode = true,
CellAlignment = TextAlignment.Near,
Title = "Resource",
TitleBackgroundColor = headerColor,
},
new ColumnDefinition
{
Title = "Type",
CellAlignment = TextAlignment.Center,
TitleBackgroundColor = headerColor,
},
new ColumnDefinition
{
Title = "References",
TitleBackgroundColor = headerColor,
},
new ColumnDefinition
{
Title = "Memory Usage",
TitleBackgroundColor = headerColor,
FormatValue = v => Utilities.Utils.FormatBytesCount((ulong)v),
},
},
Parent = layout,
};
_table.Splits = new[]
{
0.6f,
0.2f,
0.08f,
0.12f,
};
}
/// <inheritdoc />
public override void Clear()
{
_memoryUsageChart.Clear();
_resources?.Clear();
_resourceCache?.Clear();
}
/// <inheritdoc />
public override void Update(ref SharedUpdateData sharedData)
{
if (_resourceCache == null)
_resourceCache = new Dictionary<Guid, Resource>();
if (_stringBuilder == null)
_stringBuilder = new StringBuilder();
// Capture current assets usage info
var assets = FlaxEngine.Content.Assets;
var sb = _stringBuilder;
var resources = new Resource[assets.Length];
var contentDatabase = Editor.Instance.ContentDatabase;
ulong totalMemoryUsage = 0;
for (int i = 0; i < resources.Length; i++)
{
var asset = assets[i];
if (!asset)
continue;
// Try to reuse cached resource info
var assetId = asset.ID;
if (!_resourceCache.TryGetValue(assetId, out var resource))
{
resource = new Resource
{
Name = asset.Path,
TypeName = asset.TypeName,
AssetId = assetId,
};
var typeNameEnding = asset.TypeName.LastIndexOf('.');
if (typeNameEnding != -1)
resource.TypeName = resource.TypeName.Substring(typeNameEnding + 1);
var assetItem = Editor.Instance.ContentDatabase.FindAsset(assetId);
if (assetItem != null)
{
resource.Name = assetItem.NamePath;
}
if (string.IsNullOrEmpty(resource.Name) && asset.IsVirtual)
resource.Name = "<virtual>";
_resourceCache.Add(assetId, resource);
}
resource.MemoryUsage = asset.MemoryUsage;
totalMemoryUsage += resource.MemoryUsage;
resource.ReferencesCount = asset.ReferencesCount;
resources[i] = resource;
}
_memoryUsageChart.AddSample((float)totalMemoryUsage);
Array.Sort(resources, SortResources);
if (_resources == null)
_resources = new SamplesBuffer<Resource[]>();
_resources.Add(resources);
}
/// <inheritdoc />
public override void UpdateView(int selectedFrame, bool showOnlyLastUpdateEvents)
{
_memoryUsageChart.SelectedSampleIndex = selectedFrame;
if (_resources == null)
return;
if (_tableRowsCache == null)
_tableRowsCache = new List<ClickableRow>();
UpdateTable();
}
/// <inheritdoc />
public override void OnDestroy()
{
_resources?.Clear();
_resourceCache?.Clear();
_tableRowsCache?.Clear();
_stringBuilder?.Clear();
base.OnDestroy();
}
private static int SortResources(Resource a, Resource b)
{
return (int)(b.MemoryUsage - a.MemoryUsage);
}
private void UpdateTable()
{
_table.IsLayoutLocked = true;
int idx = 0;
while (_table.Children.Count > idx)
{
var child = _table.Children[idx];
if (child is ClickableRow row)
{
_tableRowsCache.Add(row);
child.Parent = null;
}
else
{
idx++;
}
}
_table.LockChildrenRecursive();
UpdateTableInner();
_table.UnlockChildrenRecursive();
_table.PerformLayout();
}
private void UpdateTableInner()
{
if (_resources.Count == 0)
return;
var resources = _resources.Get(_memoryUsageChart.SelectedSampleIndex);
if (resources == null || resources.Length == 0)
return;
// Add rows
var rowColor2 = Style.Current.Background * 1.4f;
for (int i = 0; i < resources.Length; i++)
{
ref var e = ref resources[i];
ClickableRow row;
if (_tableRowsCache.Count != 0)
{
// Reuse row
var last = _tableRowsCache.Count - 1;
row = _tableRowsCache[last];
_tableRowsCache.RemoveAt(last);
}
else
{
// Allocate new row
row = new ClickableRow { Values = new object[4] };
row.RowDoubleClick = OnRowDoubleClick;
row.RowRightClick = OnRowRightClick;
}
// Setup row data
row.Tag = e.AssetId;
row.Values[0] = e.Name;
row.Values[1] = e.TypeName;
row.Values[2] = e.ReferencesCount;
row.Values[3] = e.MemoryUsage;
// Add row to the table
row.Width = _table.Width;
row.BackgroundColor = i % 2 == 0 ? rowColor2 : Color.Transparent;
row.Parent = _table;
}
}
private void OnRowDoubleClick(ClickableRow row)
{
var assetId = (Guid)row.Tag;
var assetItem = Editor.Instance.ContentDatabase.FindAsset(assetId);
if (assetItem != null)
Editor.Instance.ContentEditing.Open(assetItem);
}
private void OnRowRightClick(ClickableRow row)
{
var assetId = (Guid)row.Tag;
var assetItem = Editor.Instance.ContentDatabase.FindAsset(assetId);
if (assetItem != null)
{
var cm = new ContextMenu();
ContextMenuButton b;
b = cm.AddButton("Open", () => Editor.Instance.ContentEditing.Open(assetItem));
cm.AddButton("Show in content window", () => Editor.Instance.Windows.ContentWin.Select(assetItem));
cm.AddButton("Show in explorer", () => FileSystem.ShowFileExplorer(System.IO.Path.GetDirectoryName(assetItem.Path)));
cm.AddButton("Select actors using this asset", () => Editor.Instance.SceneEditing.SelectActorsUsingAsset(assetItem.ID));
cm.AddButton("Show asset references graph", () => Editor.Instance.Windows.Open(new AssetReferencesGraphWindow(Editor.Instance, assetItem)));
cm.AddButton("Copy name", () => Clipboard.Text = assetItem.NamePath);
cm.AddButton("Copy path", () => Clipboard.Text = assetItem.Path);
cm.AddButton("Copy asset ID", () => Clipboard.Text = JsonSerializer.GetStringID(assetItem.ID));
cm.Show(row, row.PointFromScreen(Input.MouseScreenPosition));
}
}
}
}

View File

@@ -205,7 +205,6 @@ namespace FlaxEditor.Windows.Profiler
/// <inheritdoc /> /// <inheritdoc />
public override void OnDestroy() public override void OnDestroy()
{ {
Clear();
_timelineLabelsCache?.Clear(); _timelineLabelsCache?.Clear();
_timelineEventsCache?.Clear(); _timelineEventsCache?.Clear();
_tableRowsCache?.Clear(); _tableRowsCache?.Clear();

View File

@@ -166,7 +166,6 @@ namespace FlaxEditor.Windows.Profiler
/// <inheritdoc /> /// <inheritdoc />
public override void OnDestroy() public override void OnDestroy()
{ {
Clear();
_timelineEventsCache?.Clear(); _timelineEventsCache?.Clear();
_tableRowsCache?.Clear(); _tableRowsCache?.Clear();

View File

@@ -0,0 +1,327 @@
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
using System;
using System.Collections.Generic;
using System.Text;
using FlaxEditor.GUI;
using FlaxEngine;
using FlaxEngine.GUI;
namespace FlaxEditor.Windows.Profiler
{
/// <summary>
/// The GPU Memory profiling mode.
/// </summary>
/// <seealso cref="FlaxEditor.Windows.Profiler.ProfilerMode" />
internal sealed class MemoryGPU : ProfilerMode
{
private struct Resource
{
public string Name;
public string Tooltip;
public GPUResourceType Type;
public ulong MemoryUsage;
public Guid AssetId;
public bool IsAssetItem;
}
private readonly SingleChart _memoryUsageChart;
private readonly Table _table;
private SamplesBuffer<Resource[]> _resources;
private List<ClickableRow> _tableRowsCache;
private string[] _resourceTypesNames;
private Dictionary<string, Guid> _assetPathToId;
private Dictionary<Guid, Resource> _resourceCache;
private StringBuilder _stringBuilder;
public MemoryGPU()
: base("GPU Memory")
{
// Layout
var panel = new Panel(ScrollBars.Vertical)
{
AnchorPreset = AnchorPresets.StretchAll,
Offsets = Margin.Zero,
Parent = this,
};
var layout = new VerticalPanel
{
AnchorPreset = AnchorPresets.HorizontalStretchTop,
Offsets = Margin.Zero,
IsScrollable = true,
Parent = panel,
};
// Chart
_memoryUsageChart = new SingleChart
{
Title = "GPU Memory Usage",
FormatSample = v => Utilities.Utils.FormatBytesCount((int)v),
Parent = layout,
};
_memoryUsageChart.SelectedSampleChanged += OnSelectedSampleChanged;
// Table
var headerColor = Style.Current.LightBackground;
_table = new Table
{
Columns = new[]
{
new ColumnDefinition
{
UseExpandCollapseMode = true,
CellAlignment = TextAlignment.Near,
Title = "Resource",
TitleBackgroundColor = headerColor,
},
new ColumnDefinition
{
Title = "Type",
CellAlignment = TextAlignment.Center,
TitleBackgroundColor = headerColor,
},
new ColumnDefinition
{
Title = "Memory Usage",
TitleBackgroundColor = headerColor,
FormatValue = v => Utilities.Utils.FormatBytesCount((ulong)v),
},
},
Parent = layout,
};
_table.Splits = new[]
{
0.6f,
0.2f,
0.2f,
};
}
/// <inheritdoc />
public override void Clear()
{
_memoryUsageChart.Clear();
_resources?.Clear();
_assetPathToId?.Clear();
_resourceCache?.Clear();
}
/// <inheritdoc />
public override void Update(ref SharedUpdateData sharedData)
{
_memoryUsageChart.AddSample(sharedData.Stats.MemoryGPU.Used);
if (_resourceCache == null)
_resourceCache = new Dictionary<Guid, Resource>();
if (_assetPathToId == null)
_assetPathToId = new Dictionary<string, Guid>();
if (_stringBuilder == null)
_stringBuilder = new StringBuilder();
// Capture current GPU resources usage info
var contentDatabase = Editor.Instance.ContentDatabase;
var gpuResources = GPUDevice.Instance.Resources;
var resources = new Resource[gpuResources.Length];
var sb = _stringBuilder;
for (int i = 0; i < resources.Length; i++)
{
var gpuResource = gpuResources[i];
// Try to reuse cached resource info
var gpuResourceId = gpuResource.ID;
if (!_resourceCache.TryGetValue(gpuResourceId, out var resource))
{
resource = new Resource
{
Name = gpuResource.Name,
Type = gpuResource.ResourceType,
};
// Create tooltip
sb.Clear();
if (gpuResource is GPUTexture gpuTexture)
{
var desc = gpuTexture.Description;
sb.Append("Format: ").Append(desc.Format).AppendLine();
sb.Append("Size: ").Append(desc.Width).Append('x').Append(desc.Height);
if (desc.Depth != 1)
sb.Append('x').Append(desc.Depth);
if (desc.ArraySize != 1)
sb.Append('[').Append(desc.ArraySize).Append(']');
sb.AppendLine();
sb.Append("Mip Levels: ").Append(desc.MipLevels).AppendLine();
if (desc.IsMultiSample)
sb.Append("MSAA: ").Append('x').Append((int)desc.MultiSampleLevel).AppendLine();
sb.Append("Flags: ").Append(desc.Flags).AppendLine();
sb.Append("Usage: ").Append(desc.Usage);
}
else if (gpuResource is GPUBuffer gpuBuffer)
{
var desc = gpuBuffer.Description;
sb.Append("Format: ").Append(desc.Format).AppendLine();
sb.Append("Stride: ").Append(desc.Stride).AppendLine();
sb.Append("Elements: ").Append(desc.ElementsCount).AppendLine();
sb.Append("Flags: ").Append(desc.Flags).AppendLine();
sb.Append("Usage: ").Append(desc.Usage);
}
resource.Tooltip = _stringBuilder.ToString();
// Detect asset path in the resource name
int ext = resource.Name.LastIndexOf(".flax", StringComparison.OrdinalIgnoreCase);
if (ext != -1)
{
var assetPath = resource.Name.Substring(0, ext + 5);
if (!_assetPathToId.TryGetValue(assetPath, out resource.AssetId))
{
var asset = FlaxEngine.Content.GetAsset(assetPath);
if (asset != null)
resource.AssetId = asset.ID;
_assetPathToId.Add(assetPath, resource.AssetId);
}
var assetItem = contentDatabase.FindAsset(resource.AssetId);
if (assetItem != null)
{
resource.IsAssetItem = true;
resource.Name = assetItem.NamePath + resource.Name.Substring(ext + 5); // Use text after asset path to display (eg. subobject)
}
}
_resourceCache.Add(gpuResourceId, resource);
}
resource.MemoryUsage = gpuResource.MemoryUsage;
if (resource.MemoryUsage == 1)
resource.MemoryUsage = 0; // Sometimes GPU backend fakes memory usage as 1 to mark as allocated but not resided in actual GPU memory
resources[i] = resource;
}
Array.Sort(resources, SortResources);
if (_resources == null)
_resources = new SamplesBuffer<Resource[]>();
_resources.Add(resources);
}
/// <inheritdoc />
public override void UpdateView(int selectedFrame, bool showOnlyLastUpdateEvents)
{
_memoryUsageChart.SelectedSampleIndex = selectedFrame;
if (_resources == null)
return;
if (_tableRowsCache == null)
_tableRowsCache = new List<ClickableRow>();
if (_resourceTypesNames == null)
_resourceTypesNames = new string[(int)GPUResourceType.MAX]
{
"Render Target",
"Texture",
"Cube Texture",
"Volume Texture",
"Buffer",
"Shader",
"Pipeline State",
"Descriptor",
"Query",
"Sampler",
};
UpdateTable();
}
/// <inheritdoc />
public override void OnDestroy()
{
_resources?.Clear();
_resourceCache?.Clear();
_assetPathToId?.Clear();
_tableRowsCache?.Clear();
_stringBuilder?.Clear();
base.OnDestroy();
}
private static int SortResources(Resource a, Resource b)
{
return (int)(b.MemoryUsage - a.MemoryUsage);
}
private void UpdateTable()
{
_table.IsLayoutLocked = true;
int idx = 0;
while (_table.Children.Count > idx)
{
var child = _table.Children[idx];
if (child is ClickableRow row)
{
_tableRowsCache.Add(row);
child.Parent = null;
}
else
{
idx++;
}
}
_table.LockChildrenRecursive();
UpdateTableInner();
_table.UnlockChildrenRecursive();
_table.PerformLayout();
}
private void UpdateTableInner()
{
if (_resources.Count == 0)
return;
var resources = _resources.Get(_memoryUsageChart.SelectedSampleIndex);
if (resources == null || resources.Length == 0)
return;
// Add rows
var rowColor2 = Style.Current.Background * 1.4f;
for (int i = 0; i < resources.Length; i++)
{
ref var e = ref resources[i];
ClickableRow row;
if (_tableRowsCache.Count != 0)
{
// Reuse row
var last = _tableRowsCache.Count - 1;
row = _tableRowsCache[last];
_tableRowsCache.RemoveAt(last);
}
else
{
// Allocate new row
row = new ClickableRow { Values = new object[3] };
}
// Setup row data
row.Values[0] = e.Name;
row.Values[1] = _resourceTypesNames[(int)e.Type];
row.Values[2] = e.MemoryUsage;
// Setup row interactions
row.Tag = e;
row.TooltipText = e.Tooltip;
row.RowDoubleClick = null;
if (e.IsAssetItem)
{
row.RowDoubleClick = OnRowDoubleClickAsset;
}
// Add row to the table
row.Width = _table.Width;
row.BackgroundColor = i % 2 == 0 ? rowColor2 : Color.Transparent;
row.Parent = _table;
}
}
private void OnRowDoubleClickAsset(ClickableRow row)
{
var e = (Resource)row.Tag;
var assetItem = Editor.Instance.ContentDatabase.FindAsset(e.AssetId);
Editor.Instance.ContentEditing.Open(assetItem);
}
}
}

View File

@@ -0,0 +1,87 @@
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
using FlaxEngine;
using FlaxEngine.GUI;
namespace FlaxEditor.Windows.Profiler
{
/// <summary>
/// The network profiling mode.
/// </summary>
/// <seealso cref="FlaxEditor.Windows.Profiler.ProfilerMode" />
internal sealed class Network : ProfilerMode
{
private readonly SingleChart _dataSentChart;
private readonly SingleChart _dataReceivedChart;
private FlaxEngine.Networking.NetworkDriverStats _prevStats;
public Network()
: base("Network")
{
// Layout
var panel = new Panel(ScrollBars.Vertical)
{
AnchorPreset = AnchorPresets.StretchAll,
Offsets = Margin.Zero,
Parent = this,
};
var layout = new VerticalPanel
{
AnchorPreset = AnchorPresets.HorizontalStretchTop,
Offsets = Margin.Zero,
IsScrollable = true,
Parent = panel,
};
// Charts
_dataSentChart = new SingleChart
{
Title = "Data Sent",
FormatSample = FormatSampleBytes,
Parent = layout,
};
_dataSentChart.SelectedSampleChanged += OnSelectedSampleChanged;
_dataReceivedChart = new SingleChart
{
Title = "Data Received",
FormatSample = FormatSampleBytes,
Parent = layout,
};
_dataReceivedChart.SelectedSampleChanged += OnSelectedSampleChanged;
}
private static string FormatSampleBytes(float v)
{
return (uint)v + " bytes";
}
/// <inheritdoc />
public override void Clear()
{
_dataSentChart.Clear();
_dataReceivedChart.Clear();
}
/// <inheritdoc />
public override void Update(ref SharedUpdateData sharedData)
{
var peer = FlaxEngine.Networking.NetworkManager.Peer;
if (peer == null)
{
_prevStats = new FlaxEngine.Networking.NetworkDriverStats();
return;
}
var stats = peer.NetworkDriver.GetStats();
_dataSentChart.AddSample(Mathf.Max((long)stats.TotalDataSent - (long)_prevStats.TotalDataSent, 0));
_dataReceivedChart.AddSample(Mathf.Max((long)stats.TotalDataReceived - (long)_prevStats.TotalDataReceived, 0));
_prevStats = stats;
}
/// <inheritdoc />
public override void UpdateView(int selectedFrame, bool showOnlyLastUpdateEvents)
{
_dataSentChart.SelectedSampleIndex = selectedFrame;
_dataReceivedChart.SelectedSampleIndex = selectedFrame;
}
}
}

View File

@@ -83,6 +83,14 @@ namespace FlaxEditor.Windows.Profiler
{ {
} }
/// <inheritdoc />
public override void OnDestroy()
{
Clear();
base.OnDestroy();
}
/// <summary> /// <summary>
/// Initializes this instance. /// Initializes this instance.
/// </summary> /// </summary>

View File

@@ -52,10 +52,8 @@ namespace FlaxEditor.Windows.Profiler
if (_frameIndex != value) if (_frameIndex != value)
{ {
_frameIndex = value; _frameIndex = value;
UpdateButtons(); UpdateButtons();
if (_tabs.SelectedTab is ProfilerMode mode) UpdateView();
mode.UpdateView(_frameIndex, _showOnlyLastUpdateEvents);
} }
} }
} }
@@ -71,10 +69,8 @@ namespace FlaxEditor.Windows.Profiler
if (_showOnlyLastUpdateEvents != value) if (_showOnlyLastUpdateEvents != value)
{ {
_showOnlyLastUpdateEvents = value; _showOnlyLastUpdateEvents = value;
UpdateButtons(); UpdateButtons();
if (_tabs.SelectedTab is ProfilerMode mode) UpdateView();
mode.UpdateView(_frameIndex, _showOnlyLastUpdateEvents);
} }
} }
} }
@@ -152,7 +148,9 @@ namespace FlaxEditor.Windows.Profiler
if (_tabs.Children[i] is ProfilerMode mode) if (_tabs.Children[i] is ProfilerMode mode)
{ {
mode.Clear(); mode.Clear();
FlaxEngine.Profiler.BeginEvent("ProfilerWindow.UpdateView");
mode.UpdateView(ViewFrameIndex, _showOnlyLastUpdateEvents); mode.UpdateView(ViewFrameIndex, _showOnlyLastUpdateEvents);
FlaxEngine.Profiler.EndEvent();
} }
} }
@@ -162,7 +160,11 @@ namespace FlaxEditor.Windows.Profiler
private void OnSelectedTabChanged(Tabs tabs) private void OnSelectedTabChanged(Tabs tabs)
{ {
if (tabs.SelectedTab is ProfilerMode mode) if (tabs.SelectedTab is ProfilerMode mode)
{
FlaxEngine.Profiler.BeginEvent("ProfilerWindow.UpdateView");
mode.UpdateView(ViewFrameIndex, _showOnlyLastUpdateEvents); mode.UpdateView(ViewFrameIndex, _showOnlyLastUpdateEvents);
FlaxEngine.Profiler.EndEvent();
}
} }
private void UpdateButtons() private void UpdateButtons()
@@ -174,6 +176,16 @@ namespace FlaxEditor.Windows.Profiler
_showOnlyLastUpdateEventsButton.Checked = _showOnlyLastUpdateEvents; _showOnlyLastUpdateEventsButton.Checked = _showOnlyLastUpdateEvents;
} }
private void UpdateView()
{
if (_tabs.SelectedTab is ProfilerMode mode)
{
FlaxEngine.Profiler.BeginEvent("ProfilerWindow.UpdateView");
mode.UpdateView(_frameIndex, _showOnlyLastUpdateEvents);
FlaxEngine.Profiler.EndEvent();
}
}
/// <inheritdoc /> /// <inheritdoc />
public override void OnInit() public override void OnInit()
{ {
@@ -181,7 +193,10 @@ namespace FlaxEditor.Windows.Profiler
AddMode(new Overall()); AddMode(new Overall());
AddMode(new CPU()); AddMode(new CPU());
AddMode(new GPU()); AddMode(new GPU());
AddMode(new MemoryGPU());
AddMode(new Memory()); AddMode(new Memory());
AddMode(new Assets());
AddMode(new Network());
// Init view // Init view
_frameIndex = -1; _frameIndex = -1;
@@ -192,6 +207,8 @@ namespace FlaxEditor.Windows.Profiler
} }
UpdateButtons(); UpdateButtons();
ScriptsBuilder.ScriptsReloadEnd += Clear; // Prevent crashes if any of the profiler tabs has some scripting types cached (eg. asset type info)
} }
/// <inheritdoc /> /// <inheritdoc />
@@ -206,11 +223,19 @@ namespace FlaxEditor.Windows.Profiler
for (int i = 0; i < _tabs.ChildrenCount; i++) for (int i = 0; i < _tabs.ChildrenCount; i++)
{ {
if (_tabs.Children[i] is ProfilerMode mode) if (_tabs.Children[i] is ProfilerMode mode)
{
FlaxEngine.Profiler.BeginEvent(mode.GetType().FullName);
mode.Update(ref sharedData); mode.Update(ref sharedData);
FlaxEngine.Profiler.EndEvent();
}
} }
{ {
if (_tabs.SelectedTab is ProfilerMode mode) if (_tabs.SelectedTab is ProfilerMode mode)
{
FlaxEngine.Profiler.BeginEvent("ProfilerWindow.UpdateView");
mode.UpdateView(_frameIndex, _showOnlyLastUpdateEvents); mode.UpdateView(_frameIndex, _showOnlyLastUpdateEvents);
FlaxEngine.Profiler.EndEvent();
}
} }
sharedData.End(); sharedData.End();

View File

@@ -2,7 +2,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using FlaxEditor.GUI.Tabs; using FlaxEditor.GUI.Tabs;
using FlaxEditor.GUI.Tree; using FlaxEditor.GUI.Tree;
using FlaxEditor.Scripting; using FlaxEditor.Scripting;
@@ -100,6 +99,7 @@ namespace FlaxEditor.Windows
private TextBox _searchBox; private TextBox _searchBox;
private ContainerControl _groupSearch; private ContainerControl _groupSearch;
private Tabs _actorGroups;
/// <summary> /// <summary>
/// The editor instance. /// The editor instance.
@@ -117,8 +117,9 @@ namespace FlaxEditor.Windows
Editor = editor; Editor = editor;
Selected += tab => Editor.Windows.EditWin.Viewport.SetActiveMode<TransformGizmoMode>(); Selected += tab => Editor.Windows.EditWin.Viewport.SetActiveMode<TransformGizmoMode>();
ScriptsBuilder.ScriptsReload += OnScriptsReload; ScriptsBuilder.ScriptsReload += OnScriptsReload;
ScriptsBuilder.ScriptsReloadEnd += OnScriptsReloadEnd;
var actorGroups = new Tabs _actorGroups = new Tabs
{ {
Orientation = Orientation.Vertical, Orientation = Orientation.Vertical,
UseScroll = true, UseScroll = true,
@@ -128,74 +129,19 @@ namespace FlaxEditor.Windows
Parent = this, Parent = this,
}; };
_groupSearch = CreateGroupWithList(actorGroups, "Search", 26); _groupSearch = CreateGroupWithList(_actorGroups, "Search", 26);
_searchBox = new TextBox _searchBox = new TextBox
{ {
AnchorPreset = AnchorPresets.HorizontalStretchTop, AnchorPreset = AnchorPresets.HorizontalStretchTop,
WatermarkText = "Search...", WatermarkText = "Search...",
Parent = _groupSearch.Parent.Parent, Parent = _groupSearch.Parent.Parent,
Bounds = new Rectangle(4, 4, actorGroups.Width - 8, 18), Bounds = new Rectangle(4, 4, _actorGroups.Width - 8, 18),
}; };
_searchBox.TextChanged += OnSearchBoxTextChanged; _searchBox.TextChanged += OnSearchBoxTextChanged;
var groupBasicModels = CreateGroupWithList(actorGroups, "Basic Models"); RefreshActorTabs();
groupBasicModels.AddChild(CreateEditorAssetItem("Cube", "Primitives/Cube.flax"));
groupBasicModels.AddChild(CreateEditorAssetItem("Sphere", "Primitives/Sphere.flax"));
groupBasicModels.AddChild(CreateEditorAssetItem("Plane", "Primitives/Plane.flax"));
groupBasicModels.AddChild(CreateEditorAssetItem("Cylinder", "Primitives/Cylinder.flax"));
groupBasicModels.AddChild(CreateEditorAssetItem("Cone", "Primitives/Cone.flax"));
groupBasicModels.AddChild(CreateEditorAssetItem("Capsule", "Primitives/Capsule.flax"));
var groupLights = CreateGroupWithList(actorGroups, "Lights"); _actorGroups.SelectedTabIndex = 1;
groupLights.AddChild(CreateActorItem("Directional Light", typeof(DirectionalLight)));
groupLights.AddChild(CreateActorItem("Point Light", typeof(PointLight)));
groupLights.AddChild(CreateActorItem("Spot Light", typeof(SpotLight)));
groupLights.AddChild(CreateActorItem("Sky Light", typeof(SkyLight)));
var groupVisuals = CreateGroupWithList(actorGroups, "Visuals");
groupVisuals.AddChild(CreateActorItem("Camera", typeof(Camera)));
groupVisuals.AddChild(CreateActorItem("Environment Probe", typeof(EnvironmentProbe)));
groupVisuals.AddChild(CreateActorItem("Skybox", typeof(Skybox)));
groupVisuals.AddChild(CreateActorItem("Sky", typeof(Sky)));
groupVisuals.AddChild(CreateActorItem("Exponential Height Fog", typeof(ExponentialHeightFog)));
groupVisuals.AddChild(CreateActorItem("PostFx Volume", typeof(PostFxVolume)));
groupVisuals.AddChild(CreateActorItem("Decal", typeof(Decal)));
groupVisuals.AddChild(CreateActorItem("Particle Effect", typeof(ParticleEffect)));
var groupPhysics = CreateGroupWithList(actorGroups, "Physics");
groupPhysics.AddChild(CreateActorItem("Rigid Body", typeof(RigidBody)));
groupPhysics.AddChild(CreateActorItem("Character Controller", typeof(CharacterController)));
groupPhysics.AddChild(CreateActorItem("Box Collider", typeof(BoxCollider)));
groupPhysics.AddChild(CreateActorItem("Sphere Collider", typeof(SphereCollider)));
groupPhysics.AddChild(CreateActorItem("Capsule Collider", typeof(CapsuleCollider)));
groupPhysics.AddChild(CreateActorItem("Mesh Collider", typeof(MeshCollider)));
groupPhysics.AddChild(CreateActorItem("Fixed Joint", typeof(FixedJoint)));
groupPhysics.AddChild(CreateActorItem("Distance Joint", typeof(DistanceJoint)));
groupPhysics.AddChild(CreateActorItem("Slider Joint", typeof(SliderJoint)));
groupPhysics.AddChild(CreateActorItem("Spherical Joint", typeof(SphericalJoint)));
groupPhysics.AddChild(CreateActorItem("Hinge Joint", typeof(HingeJoint)));
groupPhysics.AddChild(CreateActorItem("D6 Joint", typeof(D6Joint)));
var groupOther = CreateGroupWithList(actorGroups, "Other");
groupOther.AddChild(CreateActorItem("Animated Model", typeof(AnimatedModel)));
groupOther.AddChild(CreateActorItem("Bone Socket", typeof(BoneSocket)));
groupOther.AddChild(CreateActorItem("CSG Box Brush", typeof(BoxBrush)));
groupOther.AddChild(CreateActorItem("Audio Source", typeof(AudioSource)));
groupOther.AddChild(CreateActorItem("Audio Listener", typeof(AudioListener)));
groupOther.AddChild(CreateActorItem("Empty Actor", typeof(EmptyActor)));
groupOther.AddChild(CreateActorItem("Scene Animation", typeof(SceneAnimationPlayer)));
groupOther.AddChild(CreateActorItem("Nav Mesh Bounds Volume", typeof(NavMeshBoundsVolume)));
groupOther.AddChild(CreateActorItem("Nav Link", typeof(NavLink)));
groupOther.AddChild(CreateActorItem("Nav Modifier Volume", typeof(NavModifierVolume)));
groupOther.AddChild(CreateActorItem("Spline", typeof(Spline)));
var groupGui = CreateGroupWithList(actorGroups, "GUI");
groupGui.AddChild(CreateActorItem("UI Control", typeof(UIControl)));
groupGui.AddChild(CreateActorItem("UI Canvas", typeof(UICanvas)));
groupGui.AddChild(CreateActorItem("Text Render", typeof(TextRender)));
groupGui.AddChild(CreateActorItem("Sprite Render", typeof(SpriteRender)));
actorGroups.SelectedTabIndex = 1;
} }
private void OnScriptsReload() private void OnScriptsReload()
@@ -206,6 +152,91 @@ namespace FlaxEditor.Windows
_groupSearch.PerformLayout(); _groupSearch.PerformLayout();
} }
private void OnScriptsReloadEnd()
{
RefreshActorTabs();
}
private void RefreshActorTabs()
{
// Remove tabs
var tabs = new List<Tab>();
foreach (var child in _actorGroups.Children)
{
if (child is Tab tab)
{
if (tab.Text != "Search")
tabs.Add(tab);
}
}
foreach (var tab in tabs)
{
var group = _actorGroups.Children.Find(T => T == tab);
group.Dispose();
}
// Setup primitives tabs
var groupBasicModels = CreateGroupWithList(_actorGroups, "Basic Models");
groupBasicModels.AddChild(CreateEditorAssetItem("Cube", "Primitives/Cube.flax"));
groupBasicModels.AddChild(CreateEditorAssetItem("Sphere", "Primitives/Sphere.flax"));
groupBasicModels.AddChild(CreateEditorAssetItem("Plane", "Primitives/Plane.flax"));
groupBasicModels.AddChild(CreateEditorAssetItem("Cylinder", "Primitives/Cylinder.flax"));
groupBasicModels.AddChild(CreateEditorAssetItem("Cone", "Primitives/Cone.flax"));
groupBasicModels.AddChild(CreateEditorAssetItem("Capsule", "Primitives/Capsule.flax"));
// Created first to order specific tabs
CreateGroupWithList(_actorGroups, "Lights");
CreateGroupWithList(_actorGroups, "Visuals");
CreateGroupWithList(_actorGroups, "Physics");
CreateGroupWithList(_actorGroups, "GUI");
CreateGroupWithList(_actorGroups, "Other");
// Add other actor types to respective tab based on attribute
foreach (var actorType in Editor.CodeEditing.Actors.Get())
{
if (actorType.IsAbstract)
continue;
ActorToolboxAttribute attribute = null;
foreach (var e in actorType.GetAttributes(false))
{
if (e is ActorToolboxAttribute actorToolboxAttribute)
{
attribute = actorToolboxAttribute;
break;
}
}
if (attribute == null)
continue;
var groupName = attribute.Group.Trim();
// Check if tab already exists and add it to the tab
var actorTabExists = false;
foreach (var child in _actorGroups.Children)
{
if (child is Tab tab)
{
if (string.Equals(tab.Text, groupName, StringComparison.OrdinalIgnoreCase))
{
var tree = tab.GetChild<Panel>().GetChild<Tree>();
if (tree != null)
{
tree.AddChild(string.IsNullOrEmpty(attribute.Name) ? CreateActorItem(Utilities.Utils.GetPropertyNameUI(actorType.Name), actorType) : CreateActorItem(attribute.Name, actorType));
tree.SortChildren();
}
actorTabExists = true;
break;
}
}
}
if (actorTabExists)
continue;
var group = CreateGroupWithList(_actorGroups, groupName);
group.AddChild(string.IsNullOrEmpty(attribute.Name) ? CreateActorItem(Utilities.Utils.GetPropertyNameUI(actorType.Name), actorType) : CreateActorItem(attribute.Name, actorType));
group.SortChildren();
}
}
private void OnSearchBoxTextChanged() private void OnSearchBoxTextChanged()
{ {
// Skip events during setup or init stuff // Skip events during setup or init stuff
@@ -218,7 +249,17 @@ namespace FlaxEditor.Windows
foreach (var actorType in Editor.CodeEditing.Actors.Get()) foreach (var actorType in Editor.CodeEditing.Actors.Get())
{ {
var text = actorType.Name; ActorToolboxAttribute attribute = null;
foreach (var e in actorType.GetAttributes(true))
{
if (e is ActorToolboxAttribute actorToolboxAttribute)
{
attribute = actorToolboxAttribute;
break;
}
}
var text = (attribute == null) ? actorType.Name : string.IsNullOrEmpty(attribute.Name) ? actorType.Name : attribute.Name;
if (!QueryFilterHelper.Match(filterText, text, out QueryFilterHelper.Range[] ranges)) if (!QueryFilterHelper.Match(filterText, text, out QueryFilterHelper.Range[] ranges))
continue; continue;
@@ -249,11 +290,6 @@ namespace FlaxEditor.Windows
return new Item(name, GUI.Drag.DragItems.GetDragData(path)); return new Item(name, GUI.Drag.DragItems.GetDragData(path));
} }
private Item CreateActorItem(string name, Type type)
{
return CreateActorItem(name, new ScriptType(type));
}
private Item CreateActorItem(string name, ScriptType type) private Item CreateActorItem(string name, ScriptType type)
{ {
return new ScriptTypeItem(name, type, GUI.Drag.DragActorType.GetDragData(type)); return new ScriptTypeItem(name, type, GUI.Drag.DragActorType.GetDragData(type));

View File

@@ -86,6 +86,11 @@ public:
{ {
return Position.GetKeyframes().Count() + Rotation.GetKeyframes().Count() + Scale.GetKeyframes().Count(); return Position.GetKeyframes().Count() + Rotation.GetKeyframes().Count() + Scale.GetKeyframes().Count();
} }
uint64 GetMemoryUsage() const
{
return NodeName.Length() * sizeof(Char) + Position.GetMemoryUsage() + Rotation.GetMemoryUsage() + Scale.GetMemoryUsage();
}
}; };
/// <summary> /// <summary>
@@ -131,6 +136,14 @@ public:
return static_cast<float>(Duration / FramesPerSecond); return static_cast<float>(Duration / FramesPerSecond);
} }
uint64 GetMemoryUsage() const
{
uint64 result = RootNodeName.Length() * sizeof(Char) + Channels.Capacity() * sizeof(NodeAnimationData);
for (const auto& e : Channels)
result += e.GetMemoryUsage();
return result;
}
/// <summary> /// <summary>
/// Gets the total amount of keyframes in the all animation channels. /// Gets the total amount of keyframes in the all animation channels.
/// </summary> /// </summary>

View File

@@ -733,6 +733,11 @@ public:
_keyframes[i].Time = _keyframes[i].Time * timeScale + timeOffset;; _keyframes[i].Time = _keyframes[i].Time * timeScale + timeOffset;;
} }
uint64 GetMemoryUsage() const
{
return _keyframes.Capacity() * sizeof(KeyFrame);
}
public: public:
FORCE_INLINE KeyFrame& operator[](int32 index) FORCE_INLINE KeyFrame& operator[](int32 index)
{ {

View File

@@ -11,7 +11,8 @@
/// <summary> /// <summary>
/// The scene animation playback actor. /// The scene animation playback actor.
/// </summary> /// </summary>
API_CLASS(Attributes = "ActorContextMenu(\"New/Other/Scene Animation\")") class FLAXENGINE_API SceneAnimationPlayer : public Actor, public IPostFxSettingsProvider API_CLASS(Attributes="ActorContextMenu(\"New/Other/Scene Animation\"), ActorToolbox(\"Other\", \"Scene Animation\")")
class FLAXENGINE_API SceneAnimationPlayer : public Actor, public IPostFxSettingsProvider
{ {
DECLARE_SCENE_OBJECT(SceneAnimationPlayer); DECLARE_SCENE_OBJECT(SceneAnimationPlayer);

View File

@@ -7,7 +7,8 @@
/// <summary> /// <summary>
/// Represents a listener that hears audio sources. For spatial audio the volume and pitch of played audio is determined by the distance, orientation and velocity differences between the source and the listener. /// Represents a listener that hears audio sources. For spatial audio the volume and pitch of played audio is determined by the distance, orientation and velocity differences between the source and the listener.
/// </summary> /// </summary>
API_CLASS(Attributes="ActorContextMenu(\"New/Audio/Audio Listener\")") class FLAXENGINE_API AudioListener : public Actor API_CLASS(Attributes="ActorContextMenu(\"New/Audio/Audio Listener\"), ActorToolbox(\"Other\")")
class FLAXENGINE_API AudioListener : public Actor
{ {
DECLARE_SCENE_OBJECT(AudioListener); DECLARE_SCENE_OBJECT(AudioListener);
private: private:

View File

@@ -132,7 +132,7 @@ void AudioSource::Play()
Clip->RequestStreamingUpdate(); Clip->RequestStreamingUpdate();
// If we are looping and streaming also update streaming buffers // If we are looping and streaming also update streaming buffers
if (_loop) if (_loop || state == States::Stopped)
RequestStreamingBuffersUpdate(); RequestStreamingBuffersUpdate();
} }
} }

View File

@@ -13,7 +13,8 @@
/// <remarks> /// <remarks>
/// Whether or not an audio source is spatial is controlled by the assigned AudioClip.The volume and the pitch of a spatial audio source is controlled by its position and the AudioListener's position/direction/velocity. /// Whether or not an audio source is spatial is controlled by the assigned AudioClip.The volume and the pitch of a spatial audio source is controlled by its position and the AudioListener's position/direction/velocity.
/// </remarks> /// </remarks>
API_CLASS(Attributes="ActorContextMenu(\"New/Audio/Audio Source\")") class FLAXENGINE_API AudioSource : public Actor API_CLASS(Attributes="ActorContextMenu(\"New/Audio/Audio Source\"), ActorToolbox(\"Other\")")
class FLAXENGINE_API AudioSource : public Actor
{ {
DECLARE_SCENE_OBJECT(AudioSource); DECLARE_SCENE_OBJECT(AudioSource);
friend class AudioStreamingHandler; friend class AudioStreamingHandler;

View File

@@ -314,6 +314,17 @@ bool Asset::ShouldDeleteFileOnUnload() const
#endif #endif
uint64 Asset::GetMemoryUsage() const
{
uint64 result = sizeof(Asset);
Locker.Lock();
if (_loadingTask)
result += sizeof(ContentLoadTask);
result += (OnLoaded.Capacity() + OnReloading.Capacity() + OnUnloaded.Capacity()) * sizeof(EventType::FunctionType);
Locker.Unlock();
return result;
}
void Asset::Reload() void Asset::Reload()
{ {
// Virtual assets are memory-only so reloading them makes no sense // Virtual assets are memory-only so reloading them makes no sense

View File

@@ -128,14 +128,17 @@ public:
} }
#if USE_EDITOR #if USE_EDITOR
/// <summary> /// <summary>
/// Determines whether this asset was marked to be deleted on unload. /// Determines whether this asset was marked to be deleted on unload.
/// </summary> /// </summary>
API_PROPERTY() bool ShouldDeleteFileOnUnload() const; API_PROPERTY() bool ShouldDeleteFileOnUnload() const;
#endif #endif
/// <summary>
/// Gets amount of CPU memory used by this resource (in bytes). It's a rough estimation. Memory may be fragmented, compressed or sub-allocated so the actual memory pressure from this resource may vary.
/// </summary>
API_PROPERTY() virtual uint64 GetMemoryUsage() const;
public: public:
/// <summary> /// <summary>
/// Reloads the asset. /// Reloads the asset.
@@ -160,7 +163,6 @@ public:
virtual void CancelStreaming(); virtual void CancelStreaming();
#if USE_EDITOR #if USE_EDITOR
/// <summary> /// <summary>
/// Gets the asset references. Supported only in Editor. /// Gets the asset references. Supported only in Editor.
/// </summary> /// </summary>
@@ -184,7 +186,6 @@ public:
/// </remarks> /// </remarks>
/// <returns>The collection of the asset ids referenced by this asset.</returns> /// <returns>The collection of the asset ids referenced by this asset.</returns>
API_FUNCTION() Array<Guid, HeapAllocation> GetReferences() const; API_FUNCTION() Array<Guid, HeapAllocation> GetReferences() const;
#endif #endif
/// <summary> /// <summary>

View File

@@ -54,8 +54,5 @@ public:
/// Gets the string. /// Gets the string.
/// </summary> /// </summary>
/// <returns>The string.</returns> /// <returns>The string.</returns>
String ToString() const String ToString() const;
{
return String::Format(TEXT("ID: {0}, TypeName: {1}, Path: \'{2}\'"), ID, TypeName, Path);
}
}; };

View File

@@ -569,6 +569,23 @@ void Animation::OnSkinnedModelUnloaded(Asset* obj)
MappingCache.Remove(i); MappingCache.Remove(i);
} }
uint64 Animation::GetMemoryUsage() const
{
Locker.Lock();
uint64 result = BinaryAsset::GetMemoryUsage();
result += sizeof(Animation) - sizeof(BinaryAsset);
result += Data.GetMemoryUsage();
result += Events.Capacity() * sizeof(Pair<String, StepCurve<AnimEventData>>);
for (const auto& e : Events)
result += e.First.Length() * sizeof(Char) + e.Second.GetMemoryUsage();
result += NestedAnims.Capacity() * sizeof(Pair<String, NestedAnimData>);
result += MappingCache.Capacity() * sizeof(Pair<String, StepCurve<AnimEventData>>);
for (const auto& e : MappingCache)
result += e.Value.Capacity() * sizeof(int32);
Locker.Unlock();
return result;
}
void Animation::OnScriptingDispose() void Animation::OnScriptingDispose()
{ {
// Dispose any events to prevent crashes (scripting is released before content) // Dispose any events to prevent crashes (scripting is released before content)

View File

@@ -152,7 +152,6 @@ public:
const NodeToChannel* GetMapping(SkinnedModel* obj); const NodeToChannel* GetMapping(SkinnedModel* obj);
#if USE_EDITOR #if USE_EDITOR
/// <summary> /// <summary>
/// Gets the animation as serialized timeline data. Used to show it in Editor. /// Gets the animation as serialized timeline data. Used to show it in Editor.
/// </summary> /// </summary>
@@ -173,7 +172,6 @@ public:
/// <remarks>The cannot be used by virtual assets.</remarks> /// <remarks>The cannot be used by virtual assets.</remarks>
/// <returns><c>true</c> failed to save data; otherwise, <c>false</c>.</returns> /// <returns><c>true</c> failed to save data; otherwise, <c>false</c>.</returns>
bool Save(const StringView& path = StringView::Empty); bool Save(const StringView& path = StringView::Empty);
#endif #endif
private: private:
@@ -181,6 +179,7 @@ private:
public: public:
// [BinaryAsset] // [BinaryAsset]
uint64 GetMemoryUsage() const override;
void OnScriptingDispose() override; void OnScriptingDispose() override;
protected: protected:

View File

@@ -482,7 +482,7 @@ void Material::InitCompilationOptions(ShaderCompilationOptions& options)
options.Macros.Add({ "MATERIAL_TESSELLATION", "MATERIAL_TESSELLATION_PHONG" }); options.Macros.Add({ "MATERIAL_TESSELLATION", "MATERIAL_TESSELLATION_PHONG" });
break; break;
} }
options.Macros.Add({ "MAX_TESSELLATION_FACTOR", Numbers[info.MaxTessellationFactor] }); options.Macros.Add({ "MAX_TESSELLATION_FACTOR", Numbers[Math::Min<int32>(info.MaxTessellationFactor, ARRAY_COUNT(Numbers) - 1)] });
} }
// Helper macros (used by the parser) // Helper macros (used by the parser)

View File

@@ -722,6 +722,7 @@ bool Model::Init(const Span<int32>& meshesCountPerLod)
{ {
auto& lod = LODs[lodIndex]; auto& lod = LODs[lodIndex];
lod._model = this; lod._model = this;
lod._lodIndex = lodIndex;
lod.ScreenSize = 1.0f; lod.ScreenSize = 1.0f;
const int32 meshesCount = meshesCountPerLod[lodIndex]; const int32 meshesCount = meshesCountPerLod[lodIndex];
if (meshesCount <= 0 || meshesCount > MODEL_MAX_MESHES) if (meshesCount <= 0 || meshesCount > MODEL_MAX_MESHES)
@@ -922,6 +923,7 @@ Asset::LoadResult Model::load()
{ {
auto& lod = LODs[lodIndex]; auto& lod = LODs[lodIndex];
lod._model = this; lod._model = this;
lod._lodIndex = lodIndex;
// Screen Size // Screen Size
stream->ReadFloat(&lod.ScreenSize); stream->ReadFloat(&lod.ScreenSize);
@@ -977,7 +979,13 @@ Asset::LoadResult Model::load()
ModelSDFHeader data; ModelSDFHeader data;
sdfStream.ReadBytes(&data, sizeof(data)); sdfStream.ReadBytes(&data, sizeof(data));
if (!SDF.Texture) if (!SDF.Texture)
SDF.Texture = GPUTexture::New(); {
String name;
#if !BUILD_RELEASE
name = GetPath() + TEXT(".SDF");
#endif
SDF.Texture = GPUDevice::Instance->CreateTexture(name);
}
if (SDF.Texture->Init(GPUTextureDescription::New3D(data.Width, data.Height, data.Depth, data.Format, GPUTextureFlags::ShaderResource, data.MipLevels))) if (SDF.Texture->Init(GPUTextureDescription::New3D(data.Width, data.Height, data.Depth, data.Format, GPUTextureFlags::ShaderResource, data.MipLevels)))
return LoadResult::Failed; return LoadResult::Failed;
SDF.LocalToUVWMul = data.LocalToUVWMul; SDF.LocalToUVWMul = data.LocalToUVWMul;

View File

@@ -64,6 +64,16 @@ bool RawDataAsset::Save(const StringView& path)
#endif #endif
uint64 RawDataAsset::GetMemoryUsage() const
{
Locker.Lock();
uint64 result = BinaryAsset::GetMemoryUsage();
result += sizeof(RawDataAsset) - sizeof(BinaryAsset);
result += Data.Count();
Locker.Unlock();
return result;
}
Asset::LoadResult RawDataAsset::load() Asset::LoadResult RawDataAsset::load()
{ {
auto chunk0 = GetChunk(0); auto chunk0 = GetChunk(0);

View File

@@ -28,6 +28,10 @@ public:
#endif #endif
public:
// [BinaryAsset]
uint64 GetMemoryUsage() const override;
protected: protected:
// [BinaryAsset] // [BinaryAsset]
LoadResult load() override; LoadResult load() override;

View File

@@ -452,6 +452,22 @@ const String& BinaryAsset::GetPath() const
#endif #endif
} }
uint64 BinaryAsset::GetMemoryUsage() const
{
Locker.Lock();
uint64 result = Asset::GetMemoryUsage();
result += sizeof(BinaryAsset) - sizeof(Asset);
result += _dependantAssets.Capacity() * sizeof(BinaryAsset*);
for (int32 i = 0; i < ASSET_FILE_DATA_CHUNKS; i++)
{
auto chunk = _header.Chunks[i];
if (chunk != nullptr && chunk->IsLoaded())
result += chunk->Size();
}
Locker.Unlock();
return result;
}
/// <summary> /// <summary>
/// Helper task used to initialize binary asset and upgrade it if need to in background. /// Helper task used to initialize binary asset and upgrade it if need to in background.
/// </summary> /// </summary>

View File

@@ -41,7 +41,6 @@ public:
FlaxStorage* Storage; FlaxStorage* Storage;
#if USE_EDITOR #if USE_EDITOR
/// <summary> /// <summary>
/// The asset metadata information. Stored in a Json format. /// The asset metadata information. Stored in a Json format.
/// </summary> /// </summary>
@@ -51,14 +50,12 @@ public:
/// Asset dependencies list used by the asset for tracking (eg. material functions used by material asset). The pair of asset ID and cached file edit time (for tracking modification). /// Asset dependencies list used by the asset for tracking (eg. material functions used by material asset). The pair of asset ID and cached file edit time (for tracking modification).
/// </summary> /// </summary>
Array<Pair<Guid, DateTime>> Dependencies; Array<Pair<Guid, DateTime>> Dependencies;
#endif #endif
public: public:
/// <summary> /// <summary>
/// Gets the asset serialized version. /// Gets the asset serialized version.
/// </summary> /// </summary>
/// <returns>Version number.</returns>
virtual uint32 GetSerializedVersion() const = 0; virtual uint32 GetSerializedVersion() const = 0;
/// <summary> /// <summary>
@@ -84,14 +81,11 @@ public:
public: public:
#if USE_EDITOR #if USE_EDITOR
#if COMPILE_WITH_ASSETS_IMPORTER #if COMPILE_WITH_ASSETS_IMPORTER
/// <summary> /// <summary>
/// Reimports asset from the source file. /// Reimports asset from the source file.
/// </summary> /// </summary>
API_FUNCTION() void Reimport() const; API_FUNCTION() void Reimport() const;
#endif #endif
/// <summary> /// <summary>
@@ -130,7 +124,6 @@ protected:
virtual void OnDependencyModified(BinaryAsset* asset) virtual void OnDependencyModified(BinaryAsset* asset)
{ {
} }
#endif #endif
protected: protected:
@@ -255,7 +248,6 @@ public:
bool LoadChunks(AssetChunksFlag chunks); bool LoadChunks(AssetChunksFlag chunks);
#if USE_EDITOR #if USE_EDITOR
/// <summary> /// <summary>
/// Saves this asset to the storage container. /// Saves this asset to the storage container.
/// </summary> /// </summary>
@@ -281,7 +273,6 @@ public:
/// <param name="silentMode">In silent mode don't reload opened storage container that is using target file.</param> /// <param name="silentMode">In silent mode don't reload opened storage container that is using target file.</param>
/// <returns>True if failed, otherwise false.</returns> /// <returns>True if failed, otherwise false.</returns>
static bool SaveToAsset(const StringView& path, AssetInitData& data, bool silentMode = false); static bool SaveToAsset(const StringView& path, AssetInitData& data, bool silentMode = false);
#endif #endif
protected: protected:
@@ -302,6 +293,7 @@ public:
void OnDeleteObject() override; void OnDeleteObject() override;
#endif #endif
const String& GetPath() const final override; const String& GetPath() const final override;
uint64 GetMemoryUsage() const override;
protected: protected:
// [Asset] // [Asset]

View File

@@ -34,6 +34,11 @@ TimeSpan Content::AssetsUnloadInterval = TimeSpan::FromSeconds(10);
Delegate<Asset*> Content::AssetDisposing; Delegate<Asset*> Content::AssetDisposing;
Delegate<Asset*> Content::AssetReloading; Delegate<Asset*> Content::AssetReloading;
String AssetInfo::ToString() const
{
return String::Format(TEXT("ID: {0}, TypeName: {1}, Path: \'{2}\'"), ID, TypeName, Path);
}
namespace namespace
{ {
// Assets // Assets

View File

@@ -93,6 +93,17 @@ const String& JsonAssetBase::GetPath() const
#endif #endif
} }
uint64 JsonAssetBase::GetMemoryUsage() const
{
Locker.Lock();
uint64 result = Asset::GetMemoryUsage();
result += sizeof(JsonAssetBase) - sizeof(Asset);
if (Data)
result += Document.GetAllocator().Capacity();
Locker.Unlock();
return result;
}
#if USE_EDITOR #if USE_EDITOR
void FindIds(ISerializable::DeserializeStream& node, Array<Guid>& output) void FindIds(ISerializable::DeserializeStream& node, Array<Guid>& output)
@@ -248,6 +259,17 @@ JsonAsset::JsonAsset(const SpawnParams& params, const AssetInfo* info)
{ {
} }
uint64 JsonAsset::GetMemoryUsage() const
{
Locker.Lock();
uint64 result = JsonAssetBase::GetMemoryUsage();
result += sizeof(JsonAsset) - sizeof(JsonAssetBase);
if (Instance && InstanceType)
result += InstanceType.GetType().Size;
Locker.Unlock();
return result;
}
Asset::LoadResult JsonAsset::loadAsset() Asset::LoadResult JsonAsset::loadAsset()
{ {
const auto result = JsonAssetBase::loadAsset(); const auto result = JsonAssetBase::loadAsset();

View File

@@ -77,6 +77,7 @@ public:
public: public:
// [Asset] // [Asset]
const String& GetPath() const override; const String& GetPath() const override;
uint64 GetMemoryUsage() const override;
#if USE_EDITOR #if USE_EDITOR
void GetReferences(Array<Guid, HeapAllocation>& output) const override; void GetReferences(Array<Guid, HeapAllocation>& output) const override;
#endif #endif
@@ -122,6 +123,10 @@ public:
return Instance && InstanceType.IsAssignableFrom(T::TypeInitializer) ? (T*)Instance : nullptr; return Instance && InstanceType.IsAssignableFrom(T::TypeInitializer) ? (T*)Instance : nullptr;
} }
public:
// [JsonAssetBase]
uint64 GetMemoryUsage() const override;
protected: protected:
// [JsonAssetBase] // [JsonAssetBase]
LoadResult loadAsset() override; LoadResult loadAsset() override;

View File

@@ -3,7 +3,6 @@
#pragma once #pragma once
#include "Engine/Threading/Task.h" #include "Engine/Threading/Task.h"
#include "Engine/Core/Types/String.h"
class Asset; class Asset;
class LoadingThread; class LoadingThread;
@@ -46,7 +45,6 @@ public:
/// <summary> /// <summary>
/// Gets a task type. /// Gets a task type.
/// </summary> /// </summary>
/// <returns>The type.</returns>
FORCE_INLINE Type GetType() const FORCE_INLINE Type GetType() const
{ {
return _type; return _type;
@@ -68,13 +66,7 @@ protected:
public: public:
// [Task] // [Task]
String ToString() const override String ToString() const override;
{
return String::Format(TEXT("Content Load Task {0} ({1})"),
ToString(GetType()),
::ToString(GetState())
);
}
protected: protected:
// [Task] // [Task]

View File

@@ -211,6 +211,11 @@ void ContentLoadingManagerService::Dispose()
Tasks.CancelAll(); Tasks.CancelAll();
} }
String ContentLoadTask::ToString() const
{
return String::Format(TEXT("Content Load Task {0} ({1})"), ToString(GetType()), (int32)GetState());
}
void ContentLoadTask::Enqueue() void ContentLoadTask::Enqueue()
{ {
Tasks.Add(this); Tasks.Add(this);

View File

@@ -0,0 +1,18 @@
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
#pragma once
#include "Engine/Core/Types/Guid.h"
/// <summary>
/// Represents the reference to the scene asset. Stores the unique ID of the scene to reference. Can be used to load the selected scene.
/// </summary>
API_STRUCT(NoDefault) struct FLAXENGINE_API SceneReference
{
DECLARE_SCRIPTING_TYPE_STRUCTURE(SceneReference);
/// <summary>
/// The identifier of the scene asset (and the scene object).
/// </summary>
API_FIELD() Guid ID;
};

View File

@@ -509,14 +509,14 @@ public:
_deletedCount = _elementsCount = 0; _deletedCount = _elementsCount = 0;
if (capacity != 0 && (capacity & (capacity - 1)) != 0) if (capacity != 0 && (capacity & (capacity - 1)) != 0)
{ {
// Align capacity value to the next power of two (if it's not) // Align capacity value to the next power of two (http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2)
capacity++; capacity--;
capacity |= capacity >> 1; capacity |= capacity >> 1;
capacity |= capacity >> 2; capacity |= capacity >> 2;
capacity |= capacity >> 4; capacity |= capacity >> 4;
capacity |= capacity >> 8; capacity |= capacity >> 8;
capacity |= capacity >> 16; capacity |= capacity >> 16;
capacity = capacity + 1; capacity++;
} }
if (capacity) if (capacity)
{ {

View File

@@ -380,14 +380,14 @@ public:
_deletedCount = _elementsCount = 0; _deletedCount = _elementsCount = 0;
if (capacity != 0 && (capacity & (capacity - 1)) != 0) if (capacity != 0 && (capacity & (capacity - 1)) != 0)
{ {
// Align capacity value to the next power of two (if it's not) // Align capacity value to the next power of two (http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2)
capacity++; capacity--;
capacity |= capacity >> 1; capacity |= capacity >> 1;
capacity |= capacity >> 2; capacity |= capacity >> 2;
capacity |= capacity >> 4; capacity |= capacity >> 4;
capacity |= capacity >> 8; capacity |= capacity >> 8;
capacity |= capacity >> 16; capacity |= capacity >> 16;
capacity = capacity + 1; capacity++;
} }
if (capacity) if (capacity)
{ {

View File

@@ -6,6 +6,7 @@
#include "Engine/Serialization/Serialization.h" #include "Engine/Serialization/Serialization.h"
#include "Engine/Content/Asset.h" #include "Engine/Content/Asset.h"
#include "Engine/Content/AssetReference.h" #include "Engine/Content/AssetReference.h"
#include "Engine/Content/SceneReference.h"
/// <summary> /// <summary>
/// The game building rendering settings. /// The game building rendering settings.
@@ -50,6 +51,12 @@ public:
/// </summary> /// </summary>
API_FIELD(Attributes="EditorOrder(1000), EditorDisplay(\"Additional Data\")") API_FIELD(Attributes="EditorOrder(1000), EditorDisplay(\"Additional Data\")")
Array<AssetReference<Asset>> AdditionalAssets; Array<AssetReference<Asset>> AdditionalAssets;
/// <summary>
/// The list of additional scenes to include into build (into root assets set).
/// </summary>
API_FIELD(Attributes="EditorOrder(1000), EditorDisplay(\"Additional Data\")")
Array<SceneReference> AdditionalScenes;
/// <summary> /// <summary>
/// The list of additional folders with assets to include into build (into root assets set). Paths relative to the project directory (or absolute). /// The list of additional folders with assets to include into build (into root assets set). Paths relative to the project directory (or absolute).

View File

@@ -557,6 +557,14 @@ public:
return count; return count;
} }
/// <summary>
/// Gets the current capacity of delegate table (amount of function to store before resizing).
/// </summary>
int32 Capacity() const
{
return (int32)Platform::AtomicRead((intptr volatile*)&_size);
}
/// <summary> /// <summary>
/// Determines whether any function is binded. /// Determines whether any function is binded.
/// </summary> /// </summary>

View File

@@ -105,14 +105,16 @@ public:
FORCE_INLINE int32 CalculateCapacityGrow(int32 capacity, int32 minCapacity) const FORCE_INLINE int32 CalculateCapacityGrow(int32 capacity, int32 minCapacity) const
{ {
if (capacity == 0) if (capacity < minCapacity)
capacity = minCapacity;
if (capacity < 8)
{ {
capacity = 8; capacity = 8;
} }
else else
{ {
// Round up to the next power of 2 and multiply by 2 // Round up to the next power of 2 and multiply by 2 (http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2)
capacity++; capacity--;
capacity |= capacity >> 1; capacity |= capacity >> 1;
capacity |= capacity >> 2; capacity |= capacity >> 2;
capacity |= capacity >> 4; capacity |= capacity >> 4;
@@ -120,8 +122,6 @@ public:
capacity |= capacity >> 16; capacity |= capacity >> 16;
capacity = (capacity + 1) * 2; capacity = (capacity + 1) * 2;
} }
if (capacity < minCapacity)
capacity = minCapacity;
return capacity; return capacity;
} }

View File

@@ -88,22 +88,14 @@ public:
} }
public: public:
// Compares two Guids for equality bool operator==(const Guid& other) const
// @param left The first Guid to compare
// @param right The second Guid to compare
// @returns True if the Guids are equal, otherwise false
friend bool operator==(const Guid& left, const Guid& right)
{ {
return ((left.A ^ right.A) | (left.B ^ right.B) | (left.C ^ right.C) | (left.D ^ right.D)) == 0; return ((A ^ other.A) | (B ^ other.B) | (C ^ other.C) | (D ^ other.D)) == 0;
} }
// Compares two Guids for inequality bool operator!=(const Guid& other) const
// @param left The first Guid to compare
// @param right The second Guid to compare
// @returns True if the GUIDs are not equal, otherwise false
friend bool operator!=(const Guid& left, const Guid& right)
{ {
return ((left.A ^ right.A) | (left.B ^ right.B) | (left.C ^ right.C) | (left.D ^ right.D)) != 0; return ((A ^ other.A) | (B ^ other.B) | (C ^ other.C) | (D ^ other.D)) != 0;
} }
// Provides access to the GUIDs components // Provides access to the GUIDs components

View File

@@ -81,14 +81,14 @@ public:
return *this; return *this;
} }
friend bool operator==(const Pair& a, const Pair& b) bool operator==(const Pair& other) const
{ {
return a.First == b.First && a.Second == b.Second; return First == other.First && Second == other.Second;
} }
friend bool operator!=(const Pair& a, const Pair& b) bool operator!=(const Pair& other) const
{ {
return a.First != b.First || a.Second != b.Second; return First != other.First || Second != other.Second;
} }
}; };

View File

@@ -2,7 +2,7 @@
#pragma once #pragma once
#include "Engine/Core/Enums.h" #include "Engine/Core/Types/BaseTypes.h"
/// <summary> /// <summary>
/// Build game header flags. /// Build game header flags.

View File

@@ -4,16 +4,8 @@ using System;
namespace FlaxEngine namespace FlaxEngine
{ {
/// <summary> partial struct SceneReference : IComparable, IComparable<Guid>, IComparable<SceneReference>
/// Represents the reference to the scene asset. Stores the unique ID of the scene to reference. Can be used to load the selected scene.
/// </summary>
public struct SceneReference : IComparable, IComparable<Guid>, IComparable<SceneReference>
{ {
/// <summary>
/// The identifier of the scene asset (and the scene object).
/// </summary>
public Guid ID;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="SceneReference"/> class. /// Initializes a new instance of the <see cref="SceneReference"/> class.
/// </summary> /// </summary>

View File

@@ -154,9 +154,9 @@ private:
const Mesh* Geo; const Mesh* Geo;
int32 Lightmap; int32 Lightmap;
friend bool operator==(const DrawKey& lhs, const DrawKey& rhs) bool operator==(const DrawKey& other) const
{ {
return lhs.Mat == rhs.Mat && lhs.Geo == rhs.Geo && lhs.Lightmap == rhs.Lightmap; return Mat == other.Mat && Geo == other.Geo && Lightmap == other.Lightmap;
} }
friend uint32 GetHash(const DrawKey& key) friend uint32 GetHash(const DrawKey& key)

View File

@@ -3,6 +3,7 @@
#include "DefaultGPUTasksExecutor.h" #include "DefaultGPUTasksExecutor.h"
#include "GPUTasksContext.h" #include "GPUTasksContext.h"
#include "GPUTask.h" #include "GPUTask.h"
#include "GPUTasksManager.h"
#include "Engine/Graphics/GPUDevice.h" #include "Engine/Graphics/GPUDevice.h"
DefaultGPUTasksExecutor::DefaultGPUTasksExecutor() DefaultGPUTasksExecutor::DefaultGPUTasksExecutor()
@@ -30,7 +31,7 @@ void DefaultGPUTasksExecutor::FrameEnd()
// Default implementation performs async operations on end of the frame which is synchronized with a rendering thread // Default implementation performs async operations on end of the frame which is synchronized with a rendering thread
GPUTask* buffer[32]; GPUTask* buffer[32];
const int32 count = GPUDevice::Instance->TasksManager.RequestWork(buffer, 32); const int32 count = GPUDevice::Instance->GetTasksManager()->RequestWork(buffer, 32);
for (int32 i = 0; i < count; i++) for (int32 i = 0; i < count; i++)
{ {
_context->Run(buffer[i]); _context->Run(buffer[i]);

View File

@@ -4,7 +4,6 @@
#include "Engine/Threading/Task.h" #include "Engine/Threading/Task.h"
#include "Engine/Platform/Platform.h" #include "Engine/Platform/Platform.h"
#include "Engine/Core/Log.h"
#include "GPUTasksContext.h" #include "GPUTasksContext.h"
class GPUResource; class GPUResource;
@@ -89,32 +88,7 @@ public:
/// Executes this task. /// Executes this task.
/// </summary> /// </summary>
/// <param name="context">The context.</param> /// <param name="context">The context.</param>
void Execute(GPUTasksContext* context) void Execute(GPUTasksContext* context);
{
// Begin
ASSERT(IsQueued() && _context == nullptr);
_state = TaskState::Running;
// Perform an operation
const auto result = run(context);
// Process result
if (IsCancelRequested())
{
_state = TaskState::Canceled;
}
else if (result != Result::Ok)
{
LOG(Warning, "\'{0}\' failed with result: {1}", ToString(), ToString(result));
OnFail();
}
else
{
// Save task completion point (for synchronization)
_syncPoint = context->GetCurrentSyncPoint();
_context = context;
}
}
/// <summary> /// <summary>
/// Action fired when asynchronous operation has been synchronized with a GPU /// Action fired when asynchronous operation has been synchronized with a GPU
@@ -154,10 +128,7 @@ protected:
public: public:
// [Task] // [Task]
String ToString() const override String ToString() const override;
{
return String::Format(TEXT("GPU Async Task {0} ({1})"), ToString(GetType()), ::ToString(GetState()));
}
protected: protected:
// [Task] // [Task]

View File

@@ -2,6 +2,7 @@
#include "GPUTasksContext.h" #include "GPUTasksContext.h"
#include "GPUTask.h" #include "GPUTask.h"
#include "Engine/Core/Log.h"
#include "Engine/Graphics/GPUDevice.h" #include "Engine/Graphics/GPUDevice.h"
#include "Engine/Threading/Threading.h" #include "Engine/Threading/Threading.h"

View File

@@ -1,6 +1,7 @@
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved. // Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
#include "GPUTasksExecutor.h" #include "GPUTasksExecutor.h"
#include "Engine/Core/Log.h"
#include "Engine/Graphics/GPUDevice.h" #include "Engine/Graphics/GPUDevice.h"
GPUTasksExecutor::~GPUTasksExecutor() GPUTasksExecutor::~GPUTasksExecutor()

View File

@@ -37,7 +37,6 @@ public:
/// <summary> /// <summary>
/// Gets the context list. /// Gets the context list.
/// </summary> /// </summary>
/// <returns>GPU contexts</returns>
FORCE_INLINE const Array<GPUTasksContext*>* GetContextList() const FORCE_INLINE const Array<GPUTasksContext*>* GetContextList() const
{ {
return &_contextList; return &_contextList;

Some files were not shown because too many files have changed in this diff Show More