diff --git a/Source/Editor/Content/Proxy/CollisionDataProxy.cs b/Source/Editor/Content/Proxy/CollisionDataProxy.cs index 154789dc5..497823636 100644 --- a/Source/Editor/Content/Proxy/CollisionDataProxy.cs +++ b/Source/Editor/Content/Proxy/CollisionDataProxy.cs @@ -135,7 +135,7 @@ namespace FlaxEditor.Content } Task.Run(() => { - Editor.CookMeshCollision(assetItem.Path, CollisionDataType.TriangleMesh, model); + Editor.CookMeshCollision(assetItem.Path, CollisionDataType.ConvexMesh, model); if (created != null) FlaxEngine.Scripting.InvokeOnUpdate(() => created(collisionData)); }); diff --git a/Source/Editor/Cooker/Steps/CookAssetsStep.cpp b/Source/Editor/Cooker/Steps/CookAssetsStep.cpp index 2aafda1a5..2558181aa 100644 --- a/Source/Editor/Cooker/Steps/CookAssetsStep.cpp +++ b/Source/Editor/Cooker/Steps/CookAssetsStep.cpp @@ -643,7 +643,7 @@ bool ProcessTextureBase(CookAssetsStep::AssetCookData& data) const auto asset = static_cast(data.Asset); const auto& assetHeader = asset->StreamingTexture()->GetHeader(); const auto format = asset->Format(); - const auto targetFormat = data.Data.Tools->GetTextureFormat(data.Data, asset, format); + auto targetFormat = data.Data.Tools->GetTextureFormat(data.Data, asset, format); CHECK_RETURN(!PixelFormatExtensions::IsTypeless(targetFormat), true); const auto streamingSettings = StreamingSettings::Get(); int32 mipLevelsMax = GPU_MAX_TEXTURE_MIP_LEVELS; @@ -654,6 +654,11 @@ bool ProcessTextureBase(CookAssetsStep::AssetCookData& data) group.MipLevelsMaxPerPlatform.TryGet(data.Data.Tools->GetPlatform(), mipLevelsMax); } + // If texture is smaller than the block size of the target format (eg. 4x4 texture using ASTC_6x6) then fallback to uncompressed + int32 blockSize = PixelFormatExtensions::ComputeBlockSize(targetFormat); + if (assetHeader->Width < blockSize || assetHeader->Height < blockSize || (blockSize != 1 && mipLevelsMax < 4)) + targetFormat = PixelFormatExtensions::FindUncompressedFormat(format); + // Faster path if don't need to modify texture for the target platform if (format == targetFormat && assetHeader->MipLevels <= mipLevelsMax) { diff --git a/Source/Editor/CustomEditors/CustomEditor.cs b/Source/Editor/CustomEditors/CustomEditor.cs index 48ada9150..7f540b767 100644 --- a/Source/Editor/CustomEditors/CustomEditor.cs +++ b/Source/Editor/CustomEditors/CustomEditor.cs @@ -536,7 +536,7 @@ namespace FlaxEditor.CustomEditors /// public void ClearReferenceValueAll() { - Values.ClearReferenceValue(); + Values?.ClearReferenceValue(); for (int i = 0; i < ChildrenEditors.Count; i++) { diff --git a/Source/Editor/CustomEditors/Dedicated/ActorEditor.cs b/Source/Editor/CustomEditors/Dedicated/ActorEditor.cs index 3699b8254..09b0e3a1f 100644 --- a/Source/Editor/CustomEditors/Dedicated/ActorEditor.cs +++ b/Source/Editor/CustomEditors/Dedicated/ActorEditor.cs @@ -164,7 +164,7 @@ namespace FlaxEditor.CustomEditors.Dedicated //Presenter.BuildLayoutOnUpdate(); // Better way is to just update the reference value using the new default instance of the prefab, created after changes apply - if (prefab && !prefab.WaitForLoaded()) + if (Values != null && prefab && !prefab.WaitForLoaded()) { var actor = (Actor)Values[0]; var prefabObjectId = actor.PrefabObjectID; diff --git a/Source/Editor/CustomEditors/Dedicated/SplineEditor.cs b/Source/Editor/CustomEditors/Dedicated/SplineEditor.cs index fbe3ffc86..9a33d82af 100644 --- a/Source/Editor/CustomEditors/Dedicated/SplineEditor.cs +++ b/Source/Editor/CustomEditors/Dedicated/SplineEditor.cs @@ -31,6 +31,11 @@ namespace FlaxEditor.CustomEditors.Dedicated /// private class EditTangentOptionBase { + /// + /// Spline editor reference. + /// + public SplineEditor Editor; + /// /// Called when user set selected tangent mode. /// @@ -103,7 +108,7 @@ namespace FlaxEditor.CustomEditors.Dedicated SetKeyframeLinear(spline, index); // change the selection to tangent parent (a spline point / keyframe) - SetSelectSplinePointNode(spline, index); + Editor.SetSelectSplinePointNode(spline, index); } } @@ -172,7 +177,7 @@ namespace FlaxEditor.CustomEditors.Dedicated public override void OnSetMode(Spline spline, int index) { SetTangentSmoothIn(spline, index); - SetSelectTangentIn(spline, index); + Editor.SetSelectTangentIn(spline, index); } } @@ -186,7 +191,7 @@ namespace FlaxEditor.CustomEditors.Dedicated public override void OnSetMode(Spline spline, int index) { SetTangentSmoothOut(spline, index); - SetSelectTangentOut(spline, index); + Editor.SetSelectTangentOut(spline, index); } } @@ -281,7 +286,7 @@ namespace FlaxEditor.CustomEditors.Dedicated { base.Initialize(layout); - _currentTangentMode = new FreeTangentMode(); + _currentTangentMode = new FreeTangentMode { Editor = this }; if (Values.HasDifferentTypes || !(Values[0] is Spline spline)) return; _selectedSpline = spline; @@ -471,7 +476,7 @@ namespace FlaxEditor.CustomEditors.Dedicated { if (_currentTangentMode is LinearTangentMode) return; - _currentTangentMode = new LinearTangentMode(); + _currentTangentMode = new LinearTangentMode { Editor = this }; _currentTangentMode.OnSetMode(_selectedSpline, _lastPointSelected.Index); } @@ -479,7 +484,7 @@ namespace FlaxEditor.CustomEditors.Dedicated { if (_currentTangentMode is FreeTangentMode) return; - _currentTangentMode = new FreeTangentMode(); + _currentTangentMode = new FreeTangentMode { Editor = this }; _currentTangentMode.OnSetMode(_selectedSpline, _lastPointSelected.Index); } @@ -487,7 +492,7 @@ namespace FlaxEditor.CustomEditors.Dedicated { if (_currentTangentMode is AlignedTangentMode) return; - _currentTangentMode = new AlignedTangentMode(); + _currentTangentMode = new AlignedTangentMode { Editor = this }; _currentTangentMode.OnSetMode(_selectedSpline, _lastPointSelected.Index); } @@ -495,7 +500,7 @@ namespace FlaxEditor.CustomEditors.Dedicated { if (_currentTangentMode is SmoothInTangentMode) return; - _currentTangentMode = new SmoothInTangentMode(); + _currentTangentMode = new SmoothInTangentMode { Editor = this }; _currentTangentMode.OnSetMode(_selectedSpline, _lastPointSelected.Index); } @@ -503,17 +508,34 @@ namespace FlaxEditor.CustomEditors.Dedicated { if (_currentTangentMode is SmoothOutTangentMode) return; - _currentTangentMode = new SmoothOutTangentMode(); + _currentTangentMode = new SmoothOutTangentMode { Editor = this }; _currentTangentMode.OnSetMode(_selectedSpline, _lastPointSelected.Index); } + private List GetSelection() + { + if (Presenter.Owner is Windows.Assets.PrefabWindow prefabWindow) + return prefabWindow.Selection; + return Editor.Instance.SceneEditing.Selection; + } + + private void Select(SceneGraphNode node) + { + if (Presenter.Owner is Windows.Assets.PrefabWindow prefabWindow) + { + prefabWindow.Select(node); + return; + } + Editor.Instance.SceneEditing.Select(node); + } + private void UpdateSelectedPoint() { // works only if select one spline if (_selectedSpline) { - var currentSelected = Editor.Instance.SceneEditing.Selection[0]; - + var selection = GetSelection(); + var currentSelected = selection.Count != 0 ? selection[0] : null; if (currentSelected == _selectedPoint) return; if (currentSelected is SplineNode.SplinePointNode selectedPoint) @@ -540,15 +562,14 @@ namespace FlaxEditor.CustomEditors.Dedicated private void UpdateSelectedTangent() { // works only if select one spline - if (_lastPointSelected == null || Editor.Instance.SceneEditing.SelectionCount != 1) + var selection = GetSelection(); + if (_lastPointSelected == null || selection.Count != 1) { _selectedTangentIn = null; _selectedTangentOut = null; return; } - - var currentSelected = Editor.Instance.SceneEditing.Selection[0]; - + var currentSelected = selection[0]; if (currentSelected is not SplineNode.SplinePointTangentNode selectedPoint) { _selectedTangentIn = null; @@ -568,10 +589,8 @@ namespace FlaxEditor.CustomEditors.Dedicated _selectedTangentIn = selectedPoint; _selectedTangentOut = null; _currentTangentMode.OnSelectTangent(_selectedSpline, index); - return; } - if (currentSelected.Transform == _selectedSpline.GetSplineTangent(index, false)) { _selectedTangentOut = selectedPoint; @@ -833,7 +852,7 @@ namespace FlaxEditor.CustomEditors.Dedicated return null; } - private static SplineNode.SplinePointTangentNode GetSplineTangentOutNode(Spline spline, int index) + private SplineNode.SplinePointTangentNode GetSplineTangentOutNode(Spline spline, int index) { var point = GetSplinePointNode(spline, index); var tangentOut = spline.GetSplineTangent(index, false); @@ -851,19 +870,19 @@ namespace FlaxEditor.CustomEditors.Dedicated return null; } - private static void SetSelectSplinePointNode(Spline spline, int index) + private void SetSelectSplinePointNode(Spline spline, int index) { - Editor.Instance.SceneEditing.Select(GetSplinePointNode(spline, index)); + Select(GetSplinePointNode(spline, index)); } - private static void SetSelectTangentIn(Spline spline, int index) + private void SetSelectTangentIn(Spline spline, int index) { - Editor.Instance.SceneEditing.Select(GetSplineTangentInNode(spline, index)); + Select(GetSplineTangentInNode(spline, index)); } - private static void SetSelectTangentOut(Spline spline, int index) + private void SetSelectTangentOut(Spline spline, int index) { - Editor.Instance.SceneEditing.Select(GetSplineTangentOutNode(spline, index)); + Select(GetSplineTangentOutNode(spline, index)); } } } diff --git a/Source/Editor/CustomEditors/Editors/ActorTransformEditor.cs b/Source/Editor/CustomEditors/Editors/ActorTransformEditor.cs index 88ce53b78..3794bffc8 100644 --- a/Source/Editor/CustomEditors/Editors/ActorTransformEditor.cs +++ b/Source/Editor/CustomEditors/Editors/ActorTransformEditor.cs @@ -111,14 +111,17 @@ namespace FlaxEditor.CustomEditors.Editors SetLinkStyle(); var textSize = FlaxEngine.GUI.Style.Current.FontMedium.MeasureText(LinkedLabel.Text.Value); _linkButton.LocalX += textSize.X + 10; - LinkedLabel.SetupContextMenu += (label, menu, editor) => + if (LinkedLabel != null) { - menu.AddSeparator(); - if (LinkValues) - menu.AddButton("Unlink", ToggleLink).LinkTooltip("Unlinks scale components from uniform scaling"); - else - menu.AddButton("Link", ToggleLink).LinkTooltip("Links scale components for uniform scaling"); - }; + LinkedLabel.SetupContextMenu += (label, menu, editor) => + { + menu.AddSeparator(); + if (LinkValues) + menu.AddButton("Unlink", ToggleLink).LinkTooltip("Unlinks scale components from uniform scaling"); + else + menu.AddButton("Link", ToggleLink).LinkTooltip("Links scale components for uniform scaling"); + }; + } // Override colors var back = FlaxEngine.GUI.Style.Current.TextBoxBackground; diff --git a/Source/Editor/CustomEditors/Editors/DoubleEditor.cs b/Source/Editor/CustomEditors/Editors/DoubleEditor.cs index 2049860c6..906e6fff0 100644 --- a/Source/Editor/CustomEditors/Editors/DoubleEditor.cs +++ b/Source/Editor/CustomEditors/Editors/DoubleEditor.cs @@ -34,13 +34,16 @@ namespace FlaxEditor.CustomEditors.Editors if (valueCategory != Utils.ValueCategory.None) { doubleValue.SetCategory(valueCategory); - LinkedLabel.SetupContextMenu += (label, menu, editor) => + if (LinkedLabel != null) { - menu.AddSeparator(); - var mb = menu.AddButton("Show formatted", bt => { doubleValue.SetCategory(bt.Checked ? valueCategory : Utils.ValueCategory.None); }); - mb.AutoCheck = true; - mb.Checked = doubleValue.ValueBox.Category != Utils.ValueCategory.None; - }; + LinkedLabel.SetupContextMenu += (label, menu, editor) => + { + menu.AddSeparator(); + var mb = menu.AddButton("Show formatted", bt => { doubleValue.SetCategory(bt.Checked ? valueCategory : Utils.ValueCategory.None); }); + mb.AutoCheck = true; + mb.Checked = doubleValue.ValueBox.Category != Utils.ValueCategory.None; + }; + } } } } diff --git a/Source/Editor/CustomEditors/Editors/FloatEditor.cs b/Source/Editor/CustomEditors/Editors/FloatEditor.cs index 9d3ff1490..85f8bb5a3 100644 --- a/Source/Editor/CustomEditors/Editors/FloatEditor.cs +++ b/Source/Editor/CustomEditors/Editors/FloatEditor.cs @@ -40,7 +40,7 @@ namespace FlaxEditor.CustomEditors.Editors _element = slider; return; } - + var floatValue = layout.FloatValue(); floatValue.ValueBox.ValueChanged += OnValueChanged; floatValue.ValueBox.SlidingEnd += ClearToken; @@ -53,13 +53,16 @@ namespace FlaxEditor.CustomEditors.Editors if (valueCategory != Utils.ValueCategory.None) { floatValue.SetCategory(valueCategory); - LinkedLabel.SetupContextMenu += (label, menu, editor) => + if (LinkedLabel != null) { - menu.AddSeparator(); - var mb = menu.AddButton("Show formatted", bt => { floatValue.SetCategory(bt.Checked ? valueCategory : Utils.ValueCategory.None); }); - mb.AutoCheck = true; - mb.Checked = floatValue.ValueBox.Category != Utils.ValueCategory.None; - }; + LinkedLabel.SetupContextMenu += (label, menu, editor) => + { + menu.AddSeparator(); + var mb = menu.AddButton("Show formatted", bt => { floatValue.SetCategory(bt.Checked ? valueCategory : Utils.ValueCategory.None); }); + mb.AutoCheck = true; + mb.Checked = floatValue.ValueBox.Category != Utils.ValueCategory.None; + }; + } } } } diff --git a/Source/Editor/CustomEditors/Editors/InputEditor.cs b/Source/Editor/CustomEditors/Editors/InputEditor.cs index 3521f35a5..5a4905206 100644 --- a/Source/Editor/CustomEditors/Editors/InputEditor.cs +++ b/Source/Editor/CustomEditors/Editors/InputEditor.cs @@ -22,7 +22,8 @@ namespace FlaxEditor.CustomEditors.Editors /// public override void Initialize(LayoutElementsContainer layout) { - LinkedLabel.SetupContextMenu += OnSetupContextMenu; + if (LinkedLabel != null) + LinkedLabel.SetupContextMenu += OnSetupContextMenu; var comboBoxElement = layout.ComboBox(); _comboBox = comboBoxElement.ComboBox; var names = new List(); diff --git a/Source/Editor/CustomEditors/Editors/QuaternionEditor.cs b/Source/Editor/CustomEditors/Editors/QuaternionEditor.cs index 7712f1a08..96f9d0646 100644 --- a/Source/Editor/CustomEditors/Editors/QuaternionEditor.cs +++ b/Source/Editor/CustomEditors/Editors/QuaternionEditor.cs @@ -59,12 +59,15 @@ namespace FlaxEditor.CustomEditors.Editors ZElement.ValueBox.ValueChanged += OnValueChanged; ZElement.ValueBox.SlidingEnd += ClearToken; - LinkedLabel.SetupContextMenu += (label, menu, editor) => + if (LinkedLabel != null) { - menu.AddSeparator(); - var value = ((Quaternion)Values[0]).EulerAngles; - menu.AddButton("Copy Euler", () => { Clipboard.Text = JsonSerializer.Serialize(value); }).TooltipText = "Copy the Euler Angles in Degrees"; - }; + LinkedLabel.SetupContextMenu += (label, menu, editor) => + { + menu.AddSeparator(); + var value = ((Quaternion)Values[0]).EulerAngles; + menu.AddButton("Copy Euler", () => { Clipboard.Text = JsonSerializer.Serialize(value); }).TooltipText = "Copy the Euler Angles in Degrees"; + }; + } } private void OnValueChanged() diff --git a/Source/Editor/CustomEditors/Editors/Vector3Editor.cs b/Source/Editor/CustomEditors/Editors/Vector3Editor.cs index e7170a22d..719fbf05d 100644 --- a/Source/Editor/CustomEditors/Editors/Vector3Editor.cs +++ b/Source/Editor/CustomEditors/Editors/Vector3Editor.cs @@ -96,18 +96,22 @@ namespace FlaxEditor.CustomEditors.Editors ZElement.SetCategory(category); ZElement.ValueBox.ValueChanged += OnZValueChanged; ZElement.ValueBox.SlidingEnd += ClearToken; - LinkedLabel.SetupContextMenu += (label, menu, editor) => + + if (LinkedLabel != null) { - menu.AddSeparator(); - var mb = menu.AddButton("Show formatted", bt => + LinkedLabel.SetupContextMenu += (label, menu, editor) => { - XElement.SetCategory(bt.Checked ? category : Utils.ValueCategory.None); - YElement.SetCategory(bt.Checked ? category : Utils.ValueCategory.None); - ZElement.SetCategory(bt.Checked ? category : Utils.ValueCategory.None); - }); - mb.AutoCheck = true; - mb.Checked = XElement.ValueBox.Category != Utils.ValueCategory.None; - }; + menu.AddSeparator(); + var mb = menu.AddButton("Show formatted", bt => + { + XElement.SetCategory(bt.Checked ? category : Utils.ValueCategory.None); + YElement.SetCategory(bt.Checked ? category : Utils.ValueCategory.None); + ZElement.SetCategory(bt.Checked ? category : Utils.ValueCategory.None); + }); + mb.AutoCheck = true; + mb.Checked = XElement.ValueBox.Category != Utils.ValueCategory.None; + }; + } } private void OnXValueChanged() @@ -294,18 +298,22 @@ namespace FlaxEditor.CustomEditors.Editors ZElement.SetCategory(category); ZElement.ValueBox.ValueChanged += OnValueChanged; ZElement.ValueBox.SlidingEnd += ClearToken; - LinkedLabel.SetupContextMenu += (label, menu, editor) => + + if (LinkedLabel != null) { - menu.AddSeparator(); - var mb = menu.AddButton("Show formatted", bt => + LinkedLabel.SetupContextMenu += (label, menu, editor) => { - XElement.SetCategory(bt.Checked ? category : Utils.ValueCategory.None); - YElement.SetCategory(bt.Checked ? category : Utils.ValueCategory.None); - ZElement.SetCategory(bt.Checked ? category : Utils.ValueCategory.None); - }); - mb.AutoCheck = true; - mb.Checked = XElement.ValueBox.Category != Utils.ValueCategory.None; - }; + menu.AddSeparator(); + var mb = menu.AddButton("Show formatted", bt => + { + XElement.SetCategory(bt.Checked ? category : Utils.ValueCategory.None); + YElement.SetCategory(bt.Checked ? category : Utils.ValueCategory.None); + ZElement.SetCategory(bt.Checked ? category : Utils.ValueCategory.None); + }); + mb.AutoCheck = true; + mb.Checked = XElement.ValueBox.Category != Utils.ValueCategory.None; + }; + } } private void OnValueChanged() diff --git a/Source/Editor/Editor.cpp b/Source/Editor/Editor.cpp index aa9f014ba..4da379fac 100644 --- a/Source/Editor/Editor.cpp +++ b/Source/Editor/Editor.cpp @@ -407,12 +407,26 @@ int32 Editor::LoadProduct() { Array projectFiles; FileSystem::DirectoryGetFiles(projectFiles, projectPath, TEXT("*.flaxproj"), DirectorySearchOption::TopDirectoryOnly); - if (projectFiles.Count() == 1) + if (projectFiles.Count() > 1) { - // Skip creating new project if it already exists - LOG(Info, "Skip creatinng new project because it already exists"); + Platform::Fatal(TEXT("Too many project files.")); + return -2; + } + else if (projectFiles.Count() == 1) + { + LOG(Info, "Skip creating new project because it already exists"); CommandLine::Options.NewProject.Reset(); } + else + { + Array files; + FileSystem::DirectoryGetFiles(files, projectPath, TEXT("*"), DirectorySearchOption::TopDirectoryOnly); + if (files.Count() > 0) + { + Platform::Fatal(String::Format(TEXT("Target project folder '{0}' is not empty."), projectPath)); + return -1; + } + } } if (CommandLine::Options.NewProject) { diff --git a/Source/Editor/Managed/ManagedEditor.Internal.cpp b/Source/Editor/Managed/ManagedEditor.Internal.cpp index 43c805bf4..b2867c2df 100644 --- a/Source/Editor/Managed/ManagedEditor.Internal.cpp +++ b/Source/Editor/Managed/ManagedEditor.Internal.cpp @@ -263,22 +263,22 @@ DEFINE_INTERNAL_CALL(MString*) EditorInternal_GetShaderAssetSourceCode(BinaryAss INTERNAL_CALL_CHECK_RETURN(obj, nullptr); if (obj->WaitForLoaded()) DebugLog::ThrowNullReference(); - auto lock = obj->Storage->Lock(); - if (obj->LoadChunk(SHADER_FILE_CHUNK_SOURCE)) return nullptr; + // Decrypt source code BytesContainer data; obj->GetChunkData(SHADER_FILE_CHUNK_SOURCE, data); + auto source = data.Get(); + auto sourceLength = data.Length(); + Encryption::DecryptBytes(data.Get(), data.Length()); + source[sourceLength - 1] = 0; - Encryption::DecryptBytes((byte*)data.Get(), data.Length()); - + // Get source and encrypt it back const StringAnsiView srcData((const char*)data.Get(), data.Length()); - const String source(srcData); - const auto str = MUtils::ToString(source); - - Encryption::EncryptBytes((byte*)data.Get(), data.Length()); + const auto str = MUtils::ToString(srcData); + Encryption::EncryptBytes(data.Get(), data.Length()); return str; } diff --git a/Source/Editor/Options/InputOptions.cs b/Source/Editor/Options/InputOptions.cs index 9bd556f20..211e8e54f 100644 --- a/Source/Editor/Options/InputOptions.cs +++ b/Source/Editor/Options/InputOptions.cs @@ -320,6 +320,10 @@ namespace FlaxEditor.Options [EditorDisplay("Viewport"), EditorOrder(1750)] public InputBinding ViewpointBottom = new InputBinding(KeyboardKeys.Numpad2); + [DefaultValue(typeof(InputBinding), "NumpadDecimal")] + [EditorDisplay("Viewport"), EditorOrder(1760)] + public InputBinding ToggleOrthographic = new InputBinding(KeyboardKeys.NumpadDecimal); + #endregion #region Interface diff --git a/Source/Editor/SceneGraph/Actors/SplineNode.cs b/Source/Editor/SceneGraph/Actors/SplineNode.cs index c57119e00..411bf29a3 100644 --- a/Source/Editor/SceneGraph/Actors/SplineNode.cs +++ b/Source/Editor/SceneGraph/Actors/SplineNode.cs @@ -49,12 +49,14 @@ namespace FlaxEditor.SceneGraph.Actors { get { - var actor = (Spline)_node.Actor; - return actor.GetSplineTransform(Index); + var actor = (Spline)_node?.Actor; + return actor?.GetSplineTransform(Index) ?? Transform.Identity; } set { - var actor = (Spline)_node.Actor; + var actor = (Spline)_node?.Actor; + if (actor == null) + return; actor.SetSplineTransform(Index, value); OnSplineEdited(actor); } @@ -308,11 +310,14 @@ namespace FlaxEditor.SceneGraph.Actors var selection = Editor.Instance.SceneEditing.Selection; if (selection.Count == 1 && selection[0] is SplinePointNode selectedPoint && selectedPoint.ParentNode == this) { - if (Input.Keyboard.GetKey(KeyboardKeys.Shift)) + var mouse = Input.Mouse; + var keyboard = Input.Keyboard; + + if (keyboard.GetKey(KeyboardKeys.Shift)) EditSplineWithSnap(selectedPoint); - var canAddSplinePoint = Input.Mouse.PositionDelta == Float2.Zero && Input.Mouse.Position != Float2.Zero; - var requestAddSplinePoint = Input.Keyboard.GetKey(KeyboardKeys.Control) && Input.Mouse.GetButtonDown(MouseButton.Right); + var canAddSplinePoint = mouse.PositionDelta == Float2.Zero && mouse.Position != Float2.Zero; + var requestAddSplinePoint = Input.Keyboard.GetKey(KeyboardKeys.Control) && mouse.GetButtonDown(MouseButton.Right); if (requestAddSplinePoint && canAddSplinePoint) AddSplinePoint(selectedPoint); } diff --git a/Source/Editor/SceneGraph/Actors/StaticModelNode.cs b/Source/Editor/SceneGraph/Actors/StaticModelNode.cs index 60be5bef9..885cbd5b5 100644 --- a/Source/Editor/SceneGraph/Actors/StaticModelNode.cs +++ b/Source/Editor/SceneGraph/Actors/StaticModelNode.cs @@ -11,6 +11,7 @@ using System.Collections.Generic; using FlaxEditor.Content; using FlaxEditor.GUI.ContextMenu; using FlaxEditor.Windows; +using FlaxEditor.Windows.Assets; using FlaxEngine; namespace FlaxEditor.SceneGraph.Actors @@ -84,76 +85,105 @@ namespace FlaxEditor.SceneGraph.Actors { base.OnContextMenu(contextMenu, window); - contextMenu.AddButton("Add collider", OnAddMeshCollider).Enabled = ((StaticModel)Actor).Model != null; + contextMenu.AddButton("Add collider", () => OnAddMeshCollider(window)).Enabled = ((StaticModel)Actor).Model != null; } - private void OnAddMeshCollider() + private void OnAddMeshCollider(EditorWindow window) { - var model = ((StaticModel)Actor).Model; - if (!model) - return; + // Allow collider to be added to evey static model selection + var selection = Array.Empty(); + if (window is SceneTreeWindow) + selection = Editor.Instance.SceneEditing.Selection.ToArray(); + else if (window is PrefabWindow prefabWindow) + selection = prefabWindow.Selection.ToArray(); - // 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 createdNodes = new List(); + foreach (var node in selection) { - var actor = new BoxCollider + if (node is not StaticModelNode staticModelNode) + continue; + + var model = ((StaticModel)staticModelNode.Actor).Model; + if (!model) + continue; + + // Special case for in-built Editor models that can use analytical collision + var modelPath = model.Path; + if (modelPath.EndsWith("/Primitives/Cube.flax", StringComparison.Ordinal)) { - StaticFlags = Actor.StaticFlags, - Transform = Actor.Transform, - }; - Root.Spawn(actor, Actor); - return; - } - if (modelPath.EndsWith("/Primitives/Sphere.flax", StringComparison.Ordinal)) - { - var actor = new SphereCollider + var actor = new BoxCollider + { + StaticFlags = staticModelNode.Actor.StaticFlags, + Transform = staticModelNode.Actor.Transform, + }; + staticModelNode.Root.Spawn(actor, staticModelNode.Actor); + createdNodes.Add(window is PrefabWindow pWindow ? pWindow.Graph.Root.Find(actor) : Editor.Instance.Scene.GetActorNode(actor)); + continue; + } + if (modelPath.EndsWith("/Primitives/Sphere.flax", StringComparison.Ordinal)) { - StaticFlags = Actor.StaticFlags, - Transform = Actor.Transform, - }; - Root.Spawn(actor, Actor); - return; - } - if (modelPath.EndsWith("/Primitives/Plane.flax", StringComparison.Ordinal)) - { - var actor = new BoxCollider + var actor = new SphereCollider + { + StaticFlags = staticModelNode.Actor.StaticFlags, + Transform = staticModelNode.Actor.Transform, + }; + staticModelNode.Root.Spawn(actor, staticModelNode.Actor); + createdNodes.Add(window is PrefabWindow pWindow ? pWindow.Graph.Root.Find(actor) : Editor.Instance.Scene.GetActorNode(actor)); + continue; + } + if (modelPath.EndsWith("/Primitives/Plane.flax", StringComparison.Ordinal)) { - StaticFlags = Actor.StaticFlags, - Transform = Actor.Transform, - Size = new Float3(100.0f, 100.0f, 1.0f), - }; - Root.Spawn(actor, Actor); - return; - } - if (modelPath.EndsWith("/Primitives/Capsule.flax", StringComparison.Ordinal)) - { - var actor = new CapsuleCollider + var actor = new BoxCollider + { + StaticFlags = staticModelNode.Actor.StaticFlags, + Transform = staticModelNode.Actor.Transform, + Size = new Float3(100.0f, 100.0f, 1.0f), + }; + staticModelNode.Root.Spawn(actor, staticModelNode.Actor); + createdNodes.Add(window is PrefabWindow pWindow ? pWindow.Graph.Root.Find(actor) : Editor.Instance.Scene.GetActorNode(actor)); + continue; + } + if (modelPath.EndsWith("/Primitives/Capsule.flax", StringComparison.Ordinal)) { - StaticFlags = Actor.StaticFlags, - Transform = Actor.Transform, - Radius = 25.0f, - Height = 50.0f, + var actor = new CapsuleCollider + { + StaticFlags = staticModelNode.Actor.StaticFlags, + Transform = staticModelNode.Actor.Transform, + Radius = 25.0f, + Height = 50.0f, + }; + Editor.Instance.SceneEditing.Spawn(actor, staticModelNode.Actor); + actor.LocalPosition = new Vector3(0, 50.0f, 0); + actor.LocalOrientation = Quaternion.Euler(0, 0, 90.0f); + createdNodes.Add(window is PrefabWindow pWindow ? pWindow.Graph.Root.Find(actor) : Editor.Instance.Scene.GetActorNode(actor)); + continue; + } + + // Create collision data (or reuse) and add collision actor + Action created = collisionData => + { + var actor = new MeshCollider + { + StaticFlags = staticModelNode.Actor.StaticFlags, + Transform = staticModelNode.Actor.Transform, + CollisionData = collisionData, + }; + staticModelNode.Root.Spawn(actor, staticModelNode.Actor); + createdNodes.Add(window is PrefabWindow pWindow ? pWindow.Graph.Root.Find(actor) : Editor.Instance.Scene.GetActorNode(actor)); }; - Editor.Instance.SceneEditing.Spawn(actor, Actor); - actor.LocalPosition = new Vector3(0, 50.0f, 0); - actor.LocalOrientation = Quaternion.Euler(0, 0, 90.0f); - return; + var collisionDataProxy = (CollisionDataProxy)Editor.Instance.ContentDatabase.GetProxy(); + collisionDataProxy.CreateCollisionDataFromModel(model, created, selection.Length == 1); } - // Create collision data (or reuse) and add collision actor - Action created = collisionData => + // Select all created nodes + if (window is SceneTreeWindow) { - var actor = new MeshCollider - { - StaticFlags = Actor.StaticFlags, - Transform = Actor.Transform, - CollisionData = collisionData, - }; - Root.Spawn(actor, Actor); - }; - var collisionDataProxy = (CollisionDataProxy)Editor.Instance.ContentDatabase.GetProxy(); - collisionDataProxy.CreateCollisionDataFromModel(model, created); + Editor.Instance.SceneEditing.Select(createdNodes); + } + else if (window is PrefabWindow pWindow) + { + pWindow.Select(createdNodes); + } } } } diff --git a/Source/Editor/Viewport/EditorViewport.cs b/Source/Editor/Viewport/EditorViewport.cs index 2eeb1e8c0..5bcc2c2b9 100644 --- a/Source/Editor/Viewport/EditorViewport.cs +++ b/Source/Editor/Viewport/EditorViewport.cs @@ -998,6 +998,7 @@ namespace FlaxEditor.Viewport InputActions.Add(options => options.CameraToggleRotation, () => _isVirtualMouseRightDown = !_isVirtualMouseRightDown); InputActions.Add(options => options.CameraIncreaseMoveSpeed, () => AdjustCameraMoveSpeed(1)); InputActions.Add(options => options.CameraDecreaseMoveSpeed, () => AdjustCameraMoveSpeed(-1)); + InputActions.Add(options => options.ToggleOrthographic, () => OnOrthographicModeToggled(null)); // Link for task event task.Begin += OnRenderBegin; diff --git a/Source/Editor/Windows/SceneTreeWindow.cs b/Source/Editor/Windows/SceneTreeWindow.cs index 9231ce970..a7e4e0e44 100644 --- a/Source/Editor/Windows/SceneTreeWindow.cs +++ b/Source/Editor/Windows/SceneTreeWindow.cs @@ -93,6 +93,7 @@ namespace FlaxEditor.Windows InputActions.Add(options => options.RotateMode, () => Editor.MainTransformGizmo.ActiveMode = TransformGizmoBase.Mode.Rotate); InputActions.Add(options => options.ScaleMode, () => Editor.MainTransformGizmo.ActiveMode = TransformGizmoBase.Mode.Scale); InputActions.Add(options => options.FocusSelection, () => Editor.Windows.EditWin.Viewport.FocusSelection()); + InputActions.Add(options => options.LockFocusSelection, () => Editor.Windows.EditWin.Viewport.LockFocusSelection()); InputActions.Add(options => options.Rename, Rename); } diff --git a/Source/Engine/ContentImporters/CreateMaterial.cpp b/Source/Engine/ContentImporters/CreateMaterial.cpp index d253da981..96cfe6ce2 100644 --- a/Source/Engine/ContentImporters/CreateMaterial.cpp +++ b/Source/Engine/ContentImporters/CreateMaterial.cpp @@ -166,14 +166,14 @@ CreateAssetResult CreateMaterial::Create(CreateAssetContext& context) // Diffuse + Mask ShaderGraphNode<>* diffuseTextureNode; - AddInput(layer, meta, MaterialGraphBoxes::Color, options.Diffuse.Texture, options.Diffuse.Color, Color::White, Float2::Zero, &diffuseTextureNode); + AddInput(layer, meta, MaterialGraphBoxes::Color, options.Diffuse.Texture, options.Diffuse.Color, Color::Black, Float2::Zero, &diffuseTextureNode); if (diffuseTextureNode && options.Diffuse.HasAlphaMask) { CONNECT(layer->Root->Boxes[static_cast(MaterialGraphBoxes::Mask)], diffuseTextureNode->Boxes[5]); } // Emissive - AddInput(layer, meta, MaterialGraphBoxes::Emissive, options.Emissive.Texture, options.Emissive.Color, Color::Transparent, Float2(0, 200)); + AddInput(layer, meta, MaterialGraphBoxes::Emissive, options.Emissive.Texture, options.Emissive.Color, Color::Black, Float2(0, 200)); // Opacity AddInput(layer, meta, MaterialGraphBoxes::Opacity, options.Opacity.Texture, options.Opacity.Value, 1.0f, Float2(0, 400)); diff --git a/Source/Engine/Graphics/Config.h b/Source/Engine/Graphics/Config.h index e55e2ecf4..6bb5496b9 100644 --- a/Source/Engine/Graphics/Config.h +++ b/Source/Engine/Graphics/Config.h @@ -40,13 +40,28 @@ // True if allow graphics profile events and markers #define GPU_ALLOW_PROFILE_EVENTS (!BUILD_RELEASE) +// True if allow hardware tessellation shaders (Hull and Domain shaders) +#ifndef GPU_ALLOW_TESSELLATION_SHADERS +#define GPU_ALLOW_TESSELLATION_SHADERS 1 +#endif + +// True if allow geometry shaders +#ifndef GPU_ALLOW_GEOMETRY_SHADERS +#define GPU_ALLOW_GEOMETRY_SHADERS 1 +#endif + // Enable/disable creating GPU resources on separate threads (otherwise only the main thread can be used) #define GPU_ENABLE_ASYNC_RESOURCES_CREATION 1 // Enable/disable force shaders recompilation #define GPU_FORCE_RECOMPILE_SHADERS 0 -// Default back buffer pixel format +// Define default back buffer(s) format +#ifndef GPU_BACK_BUFFER_PIXEL_FORMAT +#define GPU_BACK_BUFFER_PIXEL_FORMAT PixelFormat::B8G8R8A8_UNorm +#endif + +// Default depth buffer pixel format #ifndef GPU_DEPTH_BUFFER_PIXEL_FORMAT #define GPU_DEPTH_BUFFER_PIXEL_FORMAT PixelFormat::D32_Float #endif @@ -62,11 +77,6 @@ #define GPU_MAX_TEXTURE_MIP_LEVELS 15 #define GPU_MAX_TEXTURE_ARRAY_SIZE 1024 -// Define default back buffer(s) format -#ifndef GPU_BACK_BUFFER_PIXEL_FORMAT -#define GPU_BACK_BUFFER_PIXEL_FORMAT PixelFormat::B8G8R8A8_UNorm -#endif - // Validate configuration #if !ENABLE_ASSERTION #undef GPU_ENABLE_ASSERTION diff --git a/Source/Engine/Graphics/Materials/DeferredMaterialShader.cpp b/Source/Engine/Graphics/Materials/DeferredMaterialShader.cpp index 88dd34b35..a08797bdb 100644 --- a/Source/Engine/Graphics/Materials/DeferredMaterialShader.cpp +++ b/Source/Engine/Graphics/Materials/DeferredMaterialShader.cpp @@ -147,6 +147,7 @@ bool DeferredMaterialShader::Load() psDesc.DepthEnable = false; } +#if GPU_ALLOW_TESSELLATION_SHADERS // Check if use tessellation (both material and runtime supports it) const bool useTess = _info.TessellationMode != TessellationMethod::None && GPUDevice::Instance->Limits.HasTessellation; if (useTess) @@ -154,6 +155,7 @@ bool DeferredMaterialShader::Load() psDesc.HS = _shader->GetHS("HS"); psDesc.DS = _shader->GetDS("DS"); } +#endif // GBuffer Pass psDesc.VS = _shader->GetVS("VS"); diff --git a/Source/Engine/Graphics/Materials/DeformableMaterialShader.cpp b/Source/Engine/Graphics/Materials/DeformableMaterialShader.cpp index 6dd9a8dbc..f5b7f2368 100644 --- a/Source/Engine/Graphics/Materials/DeformableMaterialShader.cpp +++ b/Source/Engine/Graphics/Materials/DeformableMaterialShader.cpp @@ -115,6 +115,7 @@ bool DeformableMaterialShader::Load() psDesc.DepthEnable = (_info.FeaturesFlags & MaterialFeaturesFlags::DisableDepthTest) == MaterialFeaturesFlags::None; psDesc.DepthWriteEnable = (_info.FeaturesFlags & MaterialFeaturesFlags::DisableDepthWrite) == MaterialFeaturesFlags::None; +#if GPU_ALLOW_TESSELLATION_SHADERS // Check if use tessellation (both material and runtime supports it) const bool useTess = _info.TessellationMode != TessellationMethod::None && GPUDevice::Instance->Limits.HasTessellation; if (useTess) @@ -122,6 +123,7 @@ bool DeformableMaterialShader::Load() psDesc.HS = _shader->GetHS("HS"); psDesc.DS = _shader->GetDS("DS"); } +#endif #if USE_EDITOR if (_shader->HasShader("PS_QuadOverdraw")) diff --git a/Source/Engine/Graphics/Materials/ForwardMaterialShader.cpp b/Source/Engine/Graphics/Materials/ForwardMaterialShader.cpp index 6707fb802..eb843896c 100644 --- a/Source/Engine/Graphics/Materials/ForwardMaterialShader.cpp +++ b/Source/Engine/Graphics/Materials/ForwardMaterialShader.cpp @@ -134,6 +134,7 @@ bool ForwardMaterialShader::Load() psDesc.DepthEnable = (_info.FeaturesFlags & MaterialFeaturesFlags::DisableDepthTest) == MaterialFeaturesFlags::None; psDesc.DepthWriteEnable = (_info.FeaturesFlags & MaterialFeaturesFlags::DisableDepthWrite) == MaterialFeaturesFlags::None; +#if GPU_ALLOW_TESSELLATION_SHADERS // Check if use tessellation (both material and runtime supports it) const bool useTess = _info.TessellationMode != TessellationMethod::None && GPUDevice::Instance->Limits.HasTessellation; if (useTess) @@ -141,6 +142,7 @@ bool ForwardMaterialShader::Load() psDesc.HS = _shader->GetHS("HS"); psDesc.DS = _shader->GetDS("DS"); } +#endif #if USE_EDITOR if (_shader->HasShader("PS_QuadOverdraw")) diff --git a/Source/Engine/Graphics/Materials/TerrainMaterialShader.cpp b/Source/Engine/Graphics/Materials/TerrainMaterialShader.cpp index 19415c891..214284176 100644 --- a/Source/Engine/Graphics/Materials/TerrainMaterialShader.cpp +++ b/Source/Engine/Graphics/Materials/TerrainMaterialShader.cpp @@ -137,6 +137,7 @@ bool TerrainMaterialShader::Load() psDesc.DepthEnable = (_info.FeaturesFlags & MaterialFeaturesFlags::DisableDepthTest) == MaterialFeaturesFlags::None; psDesc.DepthWriteEnable = (_info.FeaturesFlags & MaterialFeaturesFlags::DisableDepthWrite) == MaterialFeaturesFlags::None; +#if GPU_ALLOW_TESSELLATION_SHADERS // Check if use tessellation (both material and runtime supports it) const bool useTess = _info.TessellationMode != TessellationMethod::None && GPUDevice::Instance->Limits.HasTessellation; if (useTess) @@ -144,6 +145,7 @@ bool TerrainMaterialShader::Load() psDesc.HS = _shader->GetHS("HS"); psDesc.DS = _shader->GetDS("DS"); } +#endif // Support blending but then use only emissive channel switch (_info.BlendMode) diff --git a/Source/Engine/Graphics/Models/SkeletonData.h b/Source/Engine/Graphics/Models/SkeletonData.h index c0e3d107f..16e2cf732 100644 --- a/Source/Engine/Graphics/Models/SkeletonData.h +++ b/Source/Engine/Graphics/Models/SkeletonData.h @@ -11,7 +11,7 @@ /// /// Describes a single skeleton node data. Used by the runtime. /// -API_STRUCT() struct SkeletonNode +API_STRUCT() struct FLAXENGINE_API SkeletonNode { DECLARE_SCRIPTING_TYPE_MINIMAL(SkeletonNode); @@ -34,7 +34,7 @@ API_STRUCT() struct SkeletonNode /// /// Describes a single skeleton bone data. Used by the runtime. Skeleton bones are subset of the skeleton nodes collection that are actually used by the skinned model meshes. /// -API_STRUCT() struct SkeletonBone +API_STRUCT() struct FLAXENGINE_API SkeletonBone { DECLARE_SCRIPTING_TYPE_MINIMAL(SkeletonBone); @@ -71,7 +71,7 @@ struct TIsPODType /// /// Bones are ordered so that parents always come first, allowing for hierarchical updates in a simple loop. /// -class SkeletonData +class FLAXENGINE_API SkeletonData { public: /// diff --git a/Source/Engine/Graphics/Shaders/GPUShader.cpp b/Source/Engine/Graphics/Shaders/GPUShader.cpp index e3ebe6c8b..577452a5c 100644 --- a/Source/Engine/Graphics/Shaders/GPUShader.cpp +++ b/Source/Engine/Graphics/Shaders/GPUShader.cpp @@ -129,6 +129,14 @@ bool GPUShader::Create(MemoryReadStream& stream) GPUShaderProgram* shader = CreateGPUShaderProgram(type, initializer, cache, cacheSize, stream); if (shader == nullptr) { +#if !GPU_ALLOW_TESSELLATION_SHADERS + if (type == ShaderStage::Hull || type == ShaderStage::Domain) + continue; +#endif +#if !GPU_ALLOW_GEOMETRY_SHADERS + if (type == ShaderStage::Geometry) + continue; +#endif LOG(Error, "Failed to create {} Shader program '{}' ({}).", ::ToString(type), String(initializer.Name), name); return true; } diff --git a/Source/Engine/Graphics/Shaders/GPUShader.h b/Source/Engine/Graphics/Shaders/GPUShader.h index 4c9383d0a..c48bf48b3 100644 --- a/Source/Engine/Graphics/Shaders/GPUShader.h +++ b/Source/Engine/Graphics/Shaders/GPUShader.h @@ -103,7 +103,11 @@ public: /// The shader object. API_FUNCTION() FORCE_INLINE GPUShaderProgramHS* GetHS(const StringAnsiView& name, int32 permutationIndex = 0) const { +#if GPU_ALLOW_TESSELLATION_SHADERS return static_cast(GetShader(ShaderStage::Hull, name, permutationIndex)); +#else + return nullptr; +#endif } /// @@ -114,7 +118,11 @@ public: /// The shader object. API_FUNCTION() FORCE_INLINE GPUShaderProgramDS* GetDS(const StringAnsiView& name, int32 permutationIndex = 0) const { +#if GPU_ALLOW_TESSELLATION_SHADERS return static_cast(GetShader(ShaderStage::Domain, name, permutationIndex)); +#else + return nullptr; +#endif } /// @@ -125,7 +133,11 @@ public: /// The shader object. API_FUNCTION() FORCE_INLINE GPUShaderProgramGS* GetGS(const StringAnsiView& name, int32 permutationIndex = 0) const { +#if GPU_ALLOW_GEOMETRY_SHADERS return static_cast(GetShader(ShaderStage::Geometry, name, permutationIndex)); +#else + return nullptr; +#endif } /// diff --git a/Source/Engine/Graphics/Textures/StreamingTexture.cpp b/Source/Engine/Graphics/Textures/StreamingTexture.cpp index a3927a30c..14874abf1 100644 --- a/Source/Engine/Graphics/Textures/StreamingTexture.cpp +++ b/Source/Engine/Graphics/Textures/StreamingTexture.cpp @@ -113,8 +113,9 @@ bool StreamingTexture::Create(const TextureHeader& header) if (_isBlockCompressed) { // Ensure that streaming doesn't go too low because the hardware expects the texture to be min in size of compressed texture block + const int32 blockSize = PixelFormatExtensions::ComputeBlockSize(_header.Format); int32 lastMip = header.MipLevels - 1; - while ((header.Width >> lastMip) < 4 && (header.Height >> lastMip) < 4 && lastMip > 0) + while ((header.Width >> lastMip) < blockSize && (header.Height >> lastMip) < blockSize && lastMip > 0) lastMip--; _minMipCountBlockCompressed = Math::Min(header.MipLevels - lastMip + 1, header.MipLevels); } diff --git a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUContextDX11.cpp b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUContextDX11.cpp index 316df4643..5e2bc5a84 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUContextDX11.cpp +++ b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUContextDX11.cpp @@ -49,7 +49,8 @@ GPUContextDX11::GPUContextDX11(GPUDeviceDX11* device, ID3D11DeviceContext* conte , _omDirtyFlag(false) , _rtCount(0) , _rtDepth(nullptr) - , _srDirtyFlag(false) + , _srMaskDirtyGraphics(0) + , _srMaskDirtyCompute(0) , _uaDirtyFlag(false) , _cbDirtyFlag(false) , _currentState(nullptr) @@ -80,8 +81,9 @@ void GPUContextDX11::FrameBegin() // Setup _omDirtyFlag = false; _uaDirtyFlag = false; - _srDirtyFlag = false; _cbDirtyFlag = false; + _srMaskDirtyGraphics = 0; + _srMaskDirtyCompute = 0; _rtCount = 0; _currentState = nullptr; _rtDepth = nullptr; @@ -97,9 +99,13 @@ void GPUContextDX11::FrameBegin() CurrentRasterizerState = nullptr; CurrentDepthStencilState = nullptr; CurrentVS = nullptr; +#if GPU_ALLOW_TESSELLATION_SHADERS CurrentHS = nullptr; CurrentDS = nullptr; +#endif +#if GPU_ALLOW_GEOMETRY_SHADERS CurrentGS = nullptr; +#endif CurrentPS = nullptr; CurrentCS = nullptr; CurrentPrimitiveTopology = D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED; @@ -117,7 +123,9 @@ void GPUContextDX11::FrameBegin() _device->_samplerShadowLinear }; _context->VSSetSamplers(0, ARRAY_COUNT(samplers), samplers); +#if GPU_ALLOW_TESSELLATION_SHADERS _context->DSSetSamplers(0, ARRAY_COUNT(samplers), samplers); +#endif _context->PSSetSamplers(0, ARRAY_COUNT(samplers), samplers); _context->CSSetSamplers(0, ARRAY_COUNT(samplers), samplers); } @@ -282,13 +290,18 @@ void GPUContextDX11::SetStencilRef(uint32 value) void GPUContextDX11::ResetSR() { - _srDirtyFlag = false; + _srMaskDirtyGraphics = MAX_uint32; + _srMaskDirtyCompute = MAX_uint32; Platform::MemoryClear(_srHandles, sizeof(_srHandles)); _context->VSSetShaderResources(0, ARRAY_COUNT(_srHandles), _srHandles); +#if GPU_ALLOW_TESSELLATION_SHADERS _context->HSSetShaderResources(0, ARRAY_COUNT(_srHandles), _srHandles); _context->DSSetShaderResources(0, ARRAY_COUNT(_srHandles), _srHandles); +#endif +#if GPU_ALLOW_GEOMETRY_SHADERS _context->GSSetShaderResources(0, ARRAY_COUNT(_srHandles), _srHandles); +#endif _context->PSSetShaderResources(0, ARRAY_COUNT(_srHandles), _srHandles); _context->CSSetShaderResources(0, ARRAY_COUNT(_srHandles), _srHandles); } @@ -308,9 +321,13 @@ void GPUContextDX11::ResetCB() Platform::MemoryClear(_cbHandles, sizeof(_cbHandles)); _context->VSSetConstantBuffers(0, ARRAY_COUNT(_cbHandles), _cbHandles); +#if GPU_ALLOW_TESSELLATION_SHADERS _context->HSSetConstantBuffers(0, ARRAY_COUNT(_cbHandles), _cbHandles); _context->DSSetConstantBuffers(0, ARRAY_COUNT(_cbHandles), _cbHandles); +#endif +#if GPU_ALLOW_GEOMETRY_SHADERS _context->GSSetConstantBuffers(0, ARRAY_COUNT(_cbHandles), _cbHandles); +#endif _context->PSSetConstantBuffers(0, ARRAY_COUNT(_cbHandles), _cbHandles); _context->CSSetConstantBuffers(0, ARRAY_COUNT(_cbHandles), _cbHandles); } @@ -339,7 +356,8 @@ void GPUContextDX11::BindSR(int32 slot, GPUResourceView* view) auto handle = view ? ((IShaderResourceDX11*)view->GetNativePtr())->SRV() : nullptr; if (_srHandles[slot] != handle) { - _srDirtyFlag = true; + _srMaskDirtyGraphics |= 1 << slot; + _srMaskDirtyCompute |= 1 << slot; _srHandles[slot] = handle; if (view) *view->LastRenderTime = _lastRenderTime; @@ -397,7 +415,9 @@ void GPUContextDX11::BindSampler(int32 slot, GPUSampler* sampler) { const auto samplerDX11 = sampler ? static_cast(sampler)->SamplerState : nullptr; _context->VSSetSamplers(slot, 1, &samplerDX11); +#if GPU_ALLOW_TESSELLATION_SHADERS _context->DSSetSamplers(slot, 1, &samplerDX11); +#endif _context->PSSetSamplers(slot, 1, &samplerDX11); _context->CSSetSamplers(slot, 1, &samplerDX11); } @@ -536,9 +556,13 @@ void GPUContextDX11::SetState(GPUPipelineState* state) ID3D11RasterizerState* rasterizerState = nullptr; ID3D11DepthStencilState* depthStencilState = nullptr; GPUShaderProgramVSDX11* vs = nullptr; +#if GPU_ALLOW_TESSELLATION_SHADERS GPUShaderProgramHSDX11* hs = nullptr; GPUShaderProgramDSDX11* ds = nullptr; +#endif +#if GPU_ALLOW_GEOMETRY_SHADERS GPUShaderProgramGSDX11* gs = nullptr; +#endif GPUShaderProgramPSDX11* ps = nullptr; D3D11_PRIMITIVE_TOPOLOGY primitiveTopology = D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED; @@ -552,9 +576,13 @@ void GPUContextDX11::SetState(GPUPipelineState* state) ASSERT(_currentState->VS != nullptr); vs = _currentState->VS; +#if GPU_ALLOW_TESSELLATION_SHADERS hs = _currentState->HS; ds = _currentState->DS; +#endif +#if GPU_ALLOW_GEOMETRY_SHADERS gs = _currentState->GS; +#endif ps = _currentState->PS; primitiveTopology = _currentState->PrimitiveTopology; @@ -588,6 +616,7 @@ void GPUContextDX11::SetState(GPUPipelineState* state) _context->VSSetShader(vs ? vs->GetBufferHandleDX11() : nullptr, nullptr, 0); _context->IASetInputLayout(vs ? vs->GetInputLayoutDX11() : nullptr); } +#if GPU_ALLOW_TESSELLATION_SHADERS if (CurrentHS != hs) { #if DX11_CLEAR_SR_ON_STAGE_DISABLE @@ -610,6 +639,8 @@ void GPUContextDX11::SetState(GPUPipelineState* state) CurrentDS = ds; _context->DSSetShader(ds ? ds->GetBufferHandleDX11() : nullptr, nullptr, 0); } +#endif +#if GPU_ALLOW_GEOMETRY_SHADERS if (CurrentGS != gs) { #if DX11_CLEAR_SR_ON_STAGE_DISABLE @@ -621,6 +652,7 @@ void GPUContextDX11::SetState(GPUPipelineState* state) CurrentGS = gs; _context->GSSetShader(gs ? gs->GetBufferHandleDX11() : nullptr, nullptr, 0); } +#endif if (CurrentPS != ps) { #if DX11_CLEAR_SR_ON_STAGE_DISABLE @@ -667,7 +699,9 @@ void GPUContextDX11::ClearState() _device->_samplerShadowPCF }; _context->VSSetSamplers(0, ARRAY_COUNT(samplers), samplers); +#if GPU_ALLOW_TESSELLATION_SHADERS _context->DSSetSamplers(0, ARRAY_COUNT(samplers), samplers); +#endif _context->PSSetSamplers(0, ARRAY_COUNT(samplers), samplers); _context->CSSetSamplers(0, ARRAY_COUNT(samplers), samplers); #endif @@ -802,25 +836,32 @@ void GPUContextDX11::CopySubresource(GPUResource* dstResource, uint32 dstSubreso void GPUContextDX11::flushSRVs() { - if (_srDirtyFlag) +#define FLUSH_STAGE(STAGE) if (Current##STAGE) _context->STAGE##SetShaderResources(0, ARRAY_COUNT(_srHandles), _srHandles) + if (CurrentCS) { - _srDirtyFlag = false; - - // Flush with the driver - // TODO: don't bind SRV to all stages and all slots (use mask for bind diff?) -#define FLUSH_STAGE(STAGE) \ - if (Current##STAGE) \ - { \ - _context->STAGE##SetShaderResources(0, ARRAY_COUNT(_srHandles), _srHandles); \ - } - FLUSH_STAGE(VS); - FLUSH_STAGE(HS); - FLUSH_STAGE(DS); - FLUSH_STAGE(GS); - FLUSH_STAGE(PS); - FLUSH_STAGE(CS); -#undef FLUSH_STAGE + if (_srMaskDirtyCompute) + { + _srMaskDirtyCompute = 0; + FLUSH_STAGE(CS); + } } + else + { + if (_srMaskDirtyGraphics) + { + _srMaskDirtyGraphics = 0; + FLUSH_STAGE(VS); + #if GPU_ALLOW_TESSELLATION_SHADERS + FLUSH_STAGE(HS); + FLUSH_STAGE(DS); + #endif + #if GPU_ALLOW_GEOMETRY_SHADERS + FLUSH_STAGE(GS); + #endif + FLUSH_STAGE(PS); + } + } +#undef FLUSH_STAGE } void GPUContextDX11::flushUAVs() @@ -846,15 +887,15 @@ void GPUContextDX11::flushCBs() // Flush with the driver // TODO: don't bind CBV to all stages and all slots (use mask for bind diff? eg. cache mask from last flush and check if there is a diff + include mask from diff slots?) -#define FLUSH_STAGE(STAGE) \ - if (Current##STAGE) \ - { \ - _context->STAGE##SetConstantBuffers(0, ARRAY_COUNT(_cbHandles), _cbHandles); \ - } +#define FLUSH_STAGE(STAGE) if (Current##STAGE) _context->STAGE##SetConstantBuffers(0, ARRAY_COUNT(_cbHandles), _cbHandles) FLUSH_STAGE(VS); +#if GPU_ALLOW_TESSELLATION_SHADERS FLUSH_STAGE(HS); FLUSH_STAGE(DS); +#endif +#if GPU_ALLOW_GEOMETRY_SHADERS FLUSH_STAGE(GS); +#endif FLUSH_STAGE(PS); FLUSH_STAGE(CS); #undef FLUSH_STAGE diff --git a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUContextDX11.h b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUContextDX11.h index 4540bb652..08225ca41 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUContextDX11.h +++ b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUContextDX11.h @@ -32,7 +32,8 @@ private: ID3D11RenderTargetView* _rtHandles[GPU_MAX_RT_BINDED]; // Shader Resources - bool _srDirtyFlag; + uint32 _srMaskDirtyGraphics; + uint32 _srMaskDirtyCompute; ID3D11ShaderResourceView* _srHandles[GPU_MAX_SR_BINDED]; // Unordered Access @@ -55,9 +56,13 @@ private: ID3D11RasterizerState* CurrentRasterizerState; ID3D11DepthStencilState* CurrentDepthStencilState; GPUShaderProgramVSDX11* CurrentVS; +#if GPU_ALLOW_TESSELLATION_SHADERS GPUShaderProgramHSDX11* CurrentHS; GPUShaderProgramDSDX11* CurrentDS; +#endif +#if GPU_ALLOW_GEOMETRY_SHADERS GPUShaderProgramGSDX11* CurrentGS; +#endif GPUShaderProgramPSDX11* CurrentPS; GPUShaderProgramCSDX11* CurrentCS; D3D11_PRIMITIVE_TOPOLOGY CurrentPrimitiveTopology; diff --git a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.cpp b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.cpp index 81a56b43a..07bd0ec69 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.cpp +++ b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.cpp @@ -342,8 +342,8 @@ bool GPUDeviceDX11::Init() D3D11_FEATURE_DATA_D3D11_OPTIONS2 featureDataD3D11Options2 = {}; _device->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS2, &featureDataD3D11Options2, sizeof(featureDataD3D11Options2)); limits.HasCompute = d3D10XHardwareOptions.ComputeShaders_Plus_RawAndStructuredBuffers_Via_Shader_4_x != 0; - limits.HasTessellation = true; - limits.HasGeometryShaders = true; + limits.HasTessellation = GPU_ALLOW_TESSELLATION_SHADERS; + limits.HasGeometryShaders = GPU_ALLOW_GEOMETRY_SHADERS; limits.HasInstancing = true; limits.HasVolumeTextureRendering = true; limits.HasDrawIndirect = true; @@ -367,7 +367,7 @@ bool GPUDeviceDX11::Init() { limits.HasCompute = false; limits.HasTessellation = false; - limits.HasGeometryShaders = true; + limits.HasGeometryShaders = GPU_ALLOW_GEOMETRY_SHADERS; limits.HasInstancing = true; limits.HasVolumeTextureRendering = false; limits.HasDrawIndirect = false; diff --git a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUPipelineStateDX11.cpp b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUPipelineStateDX11.cpp index c80677d89..b1517b4fb 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUPipelineStateDX11.cpp +++ b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUPipelineStateDX11.cpp @@ -8,9 +8,13 @@ void GPUPipelineStateDX11::OnReleaseGPU() { BlendState = nullptr; VS = nullptr; +#if GPU_ALLOW_TESSELLATION_SHADERS HS = nullptr; DS = nullptr; +#endif +#if GPU_ALLOW_GEOMETRY_SHADERS GS = nullptr; +#endif PS = nullptr; } @@ -30,9 +34,13 @@ bool GPUPipelineStateDX11::Init(const Description& desc) // Cache shaders VS = (GPUShaderProgramVSDX11*)desc.VS; +#if GPU_ALLOW_TESSELLATION_SHADERS HS = desc.HS ? (GPUShaderProgramHSDX11*)desc.HS : nullptr; DS = desc.DS ? (GPUShaderProgramDSDX11*)desc.DS : nullptr; +#endif +#if GPU_ALLOW_GEOMETRY_SHADERS GS = desc.GS ? (GPUShaderProgramGSDX11*)desc.GS : nullptr; +#endif PS = desc.PS ? (GPUShaderProgramPSDX11*)desc.PS : nullptr; // Primitive Topology @@ -44,8 +52,10 @@ bool GPUPipelineStateDX11::Init(const Description& desc) D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST, }; PrimitiveTopology = D3D11_primTypes[static_cast(desc.PrimitiveTopology)]; +#if GPU_ALLOW_TESSELLATION_SHADERS if (HS) PrimitiveTopology = (D3D11_PRIMITIVE_TOPOLOGY)((int32)D3D11_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST + (HS->GetControlPointsCount() - 1)); +#endif // States DepthStencilStateIndex = static_cast(desc.DepthFunc) + (desc.DepthEnable ? 0 : 9) + (desc.DepthWriteEnable ? 0 : 18); diff --git a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUPipelineStateDX11.h b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUPipelineStateDX11.h index 2df72358f..0fad61f70 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUPipelineStateDX11.h +++ b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUPipelineStateDX11.h @@ -19,9 +19,13 @@ public: int32 RasterizerStateIndex; ID3D11BlendState* BlendState = nullptr; GPUShaderProgramVSDX11* VS = nullptr; +#if GPU_ALLOW_TESSELLATION_SHADERS GPUShaderProgramHSDX11* HS = nullptr; GPUShaderProgramDSDX11* DS = nullptr; +#endif +#if GPU_ALLOW_GEOMETRY_SHADERS GPUShaderProgramGSDX11* GS = nullptr; +#endif GPUShaderProgramPSDX11* PS = nullptr; D3D11_PRIMITIVE_TOPOLOGY PrimitiveTopology; diff --git a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUShaderDX11.cpp b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUShaderDX11.cpp index 7bd0d7ebb..70018233d 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUShaderDX11.cpp +++ b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUShaderDX11.cpp @@ -92,6 +92,7 @@ GPUShaderProgram* GPUShaderDX11::CreateGPUShaderProgram(ShaderStage type, const shader = New(initializer, buffer, inputLayout, inputLayoutSize); break; } +#if GPU_ALLOW_TESSELLATION_SHADERS case ShaderStage::Hull: { // Read control points @@ -118,6 +119,15 @@ GPUShaderProgram* GPUShaderDX11::CreateGPUShaderProgram(ShaderStage type, const shader = New(initializer, buffer); break; } +#else + case ShaderStage::Hull: + { + int32 controlPointsCount; + stream.ReadInt32(&controlPointsCount); + break; + } +#endif +#if GPU_ALLOW_GEOMETRY_SHADERS case ShaderStage::Geometry: { // Create shader @@ -129,6 +139,7 @@ GPUShaderProgram* GPUShaderDX11::CreateGPUShaderProgram(ShaderStage type, const shader = New(initializer, buffer); break; } +#endif case ShaderStage::Pixel: { // Create shader diff --git a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUShaderProgramDX11.h b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUShaderProgramDX11.h index 9bb4de30a..246a5e24b 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUShaderProgramDX11.h +++ b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUShaderProgramDX11.h @@ -122,6 +122,7 @@ public: } }; +#if GPU_ALLOW_TESSELLATION_SHADERS /// /// Hull Shader for DirectX 11 backend. /// @@ -159,7 +160,9 @@ public: { } }; +#endif +#if GPU_ALLOW_GEOMETRY_SHADERS /// /// Geometry Shader for DirectX 11 backend. /// @@ -177,6 +180,7 @@ public: { } }; +#endif /// /// Pixel Shader for DirectX 11 backend. diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp index 859c8b503..b070a34d0 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp +++ b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp @@ -373,8 +373,8 @@ bool GPUDeviceDX12::Init() { auto& limits = Limits; limits.HasCompute = true; - limits.HasTessellation = true; - limits.HasGeometryShaders = true; + limits.HasTessellation = GPU_ALLOW_TESSELLATION_SHADERS; + limits.HasGeometryShaders = GPU_ALLOW_GEOMETRY_SHADERS; limits.HasInstancing = true; limits.HasVolumeTextureRendering = true; limits.HasDrawIndirect = true; diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUPipelineStateDX12.cpp b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUPipelineStateDX12.cpp index 6515201fe..ead13f149 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUPipelineStateDX12.cpp +++ b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUPipelineStateDX12.cpp @@ -163,9 +163,13 @@ bool GPUPipelineStateDX12::Init(const Description& desc) if (shader->Header.UaDimensions[i]) \ Header.UaDimensions[i] = shader->Header.UaDimensions[i]; \ } +#if GPU_ALLOW_TESSELLATION_SHADERS INIT_SHADER_STAGE(HS, GPUShaderProgramHSDX12); INIT_SHADER_STAGE(DS, GPUShaderProgramDSDX12); +#endif +#if GPU_ALLOW_GEOMETRY_SHADERS INIT_SHADER_STAGE(GS, GPUShaderProgramGSDX12); +#endif INIT_SHADER_STAGE(VS, GPUShaderProgramVSDX12); INIT_SHADER_STAGE(PS, GPUShaderProgramPSDX12); const static D3D12_PRIMITIVE_TOPOLOGY_TYPE primTypes1[] = @@ -184,11 +188,13 @@ bool GPUPipelineStateDX12::Init(const Description& desc) }; psDesc.PrimitiveTopologyType = primTypes1[(int32)desc.PrimitiveTopology]; PrimitiveTopology = primTypes2[(int32)desc.PrimitiveTopology]; +#if GPU_ALLOW_TESSELLATION_SHADERS if (desc.HS) { psDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH; PrimitiveTopology = (D3D_PRIMITIVE_TOPOLOGY)((int32)D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST + (desc.HS->GetControlPointsCount() - 1)); } +#endif // Depth State psDesc.DepthStencilState.DepthEnable = !!desc.DepthEnable; diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUShaderDX12.cpp b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUShaderDX12.cpp index 964a4eb6b..638e1b409 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUShaderDX12.cpp +++ b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUShaderDX12.cpp @@ -85,6 +85,7 @@ GPUShaderProgram* GPUShaderDX12::CreateGPUShaderProgram(ShaderStage type, const shader = New(initializer, header, cacheBytes, cacheSize, inputLayout, inputLayoutSize); break; } +#if GPU_ALLOW_TESSELLATION_SHADERS case ShaderStage::Hull: { int32 controlPointsCount; @@ -97,11 +98,21 @@ GPUShaderProgram* GPUShaderDX12::CreateGPUShaderProgram(ShaderStage type, const shader = New(initializer, header, cacheBytes, cacheSize); break; } +#else + case ShaderStage::Hull: + { + int32 controlPointsCount; + stream.ReadInt32(&controlPointsCount); + break; + } +#endif +#if GPU_ALLOW_GEOMETRY_SHADERS case ShaderStage::Geometry: { shader = New(initializer, header, cacheBytes, cacheSize); break; } +#endif case ShaderStage::Pixel: { shader = New(initializer, header, cacheBytes, cacheSize); diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUShaderProgramDX12.h b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUShaderProgramDX12.h index d7a12ef64..843666307 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUShaderProgramDX12.h +++ b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUShaderProgramDX12.h @@ -79,6 +79,7 @@ public: } }; +#if GPU_ALLOW_TESSELLATION_SHADERS /// /// Hull Shader for DirectX 12 backend. /// @@ -105,7 +106,9 @@ public: { } }; +#endif +#if GPU_ALLOW_GEOMETRY_SHADERS /// /// Geometry Shader for DirectX 12 backend. /// @@ -118,6 +121,7 @@ public: { } }; +#endif /// /// Pixel Shader for DirectX 12 backend. diff --git a/Source/Engine/GraphicsDevice/Vulkan/Android/AndroidVulkanPlatform.h b/Source/Engine/GraphicsDevice/Vulkan/Android/AndroidVulkanPlatform.h index ad0c49b0a..ad2d68652 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/Android/AndroidVulkanPlatform.h +++ b/Source/Engine/GraphicsDevice/Vulkan/Android/AndroidVulkanPlatform.h @@ -6,6 +6,9 @@ #if GRAPHICS_API_VULKAN && PLATFORM_ANDROID +// Support more backbuffers in case driver decides to use more +#define VULKAN_BACK_BUFFERS_COUNT_MAX 8 + /// /// The implementation for the Vulkan API support for Android platform. /// diff --git a/Source/Engine/GraphicsDevice/Vulkan/DescriptorSetVulkan.h b/Source/Engine/GraphicsDevice/Vulkan/DescriptorSetVulkan.h index 8a5d706d6..1b3de5eaa 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/DescriptorSetVulkan.h +++ b/Source/Engine/GraphicsDevice/Vulkan/DescriptorSetVulkan.h @@ -25,21 +25,25 @@ namespace DescriptorSet enum Stage { // Vertex shader stage - Vertex = 0, + Vertex, // Pixel shader stage - Pixel = 1, + Pixel, +#if GPU_ALLOW_GEOMETRY_SHADERS // Geometry shader stage - Geometry = 2, + Geometry, +#endif +#if GPU_ALLOW_TESSELLATION_SHADERS // Hull shader stage - Hull = 3, + Hull, // Domain shader stage - Domain = 4, + Domain, +#endif // Graphics pipeline stages count - GraphicsStagesCount = 5, + GraphicsStagesCount, // Compute pipeline slot Compute = 0, // The maximum amount of slots for all stages - Max = 5, + Max = GraphicsStagesCount, }; template diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp index 71a154ae8..565037e47 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp @@ -1686,15 +1686,15 @@ bool GPUDeviceVulkan::Init() auto& limits = Limits; limits.HasCompute = GetShaderProfile() == ShaderProfile::Vulkan_SM5 && PhysicalDeviceLimits.maxComputeWorkGroupCount[0] >= GPU_MAX_CS_DISPATCH_THREAD_GROUPS && PhysicalDeviceLimits.maxComputeWorkGroupCount[1] >= GPU_MAX_CS_DISPATCH_THREAD_GROUPS; -#if PLATFORM_MAC || PLATFORM_IOS - limits.HasTessellation = false; // MoltenVK has artifacts when using tess -#else +#if GPU_ALLOW_TESSELLATION_SHADERS limits.HasTessellation = !!PhysicalDeviceFeatures.tessellationShader && PhysicalDeviceLimits.maxBoundDescriptorSets > (uint32_t)DescriptorSet::Domain; -#endif -#if PLATFORM_ANDROID || PLATFORM_IOS - limits.HasGeometryShaders = false; // Don't even try GS on mobile #else - limits.HasGeometryShaders = !!PhysicalDeviceFeatures.geometryShader; + limits.HasTessellation = false; +#endif +#if GPU_ALLOW_GEOMETRY_SHADERS + limits.HasGeometryShaders = !!PhysicalDeviceFeatures.geometryShader && PhysicalDeviceLimits.maxBoundDescriptorSets > (uint32_t)DescriptorSet::Geometry; +#else + limits.HasGeometryShaders = false; #endif limits.HasInstancing = true; limits.HasVolumeTextureRendering = true; diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUPipelineStateVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUPipelineStateVulkan.cpp index 5fd40fdbb..7686d9c5b 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUPipelineStateVulkan.cpp +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUPipelineStateVulkan.cpp @@ -133,17 +133,19 @@ PipelineLayoutVulkan* GPUPipelineStateVulkan::GetLayout() return _layout; DescriptorSetLayoutInfoVulkan descriptorSetLayoutInfo; - #define INIT_SHADER_STAGE(set, bit) \ if (DescriptorInfoPerStage[DescriptorSet::set]) \ descriptorSetLayoutInfo.AddBindingsForStage(bit, DescriptorSet::set, DescriptorInfoPerStage[DescriptorSet::set]) INIT_SHADER_STAGE(Vertex, VK_SHADER_STAGE_VERTEX_BIT); +#if GPU_ALLOW_TESSELLATION_SHADERS INIT_SHADER_STAGE(Hull, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT); INIT_SHADER_STAGE(Domain, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT); +#endif +#if GPU_ALLOW_GEOMETRY_SHADERS INIT_SHADER_STAGE(Geometry, VK_SHADER_STAGE_GEOMETRY_BIT); +#endif INIT_SHADER_STAGE(Pixel, VK_SHADER_STAGE_FRAGMENT_BIT); #undef INIT_SHADER_STAGE - _layout = _device->GetOrCreateLayout(descriptorSetLayoutInfo); ASSERT(_layout); DescriptorSetsLayout = &_layout->DescriptorSetLayout; @@ -253,9 +255,13 @@ bool GPUPipelineStateVulkan::Init(const Description& desc) stage.pName = desc.type->GetName().Get(); \ } INIT_SHADER_STAGE(VS, Vertex, VK_SHADER_STAGE_VERTEX_BIT); +#if GPU_ALLOW_TESSELLATION_SHADERS INIT_SHADER_STAGE(HS, Hull, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT); INIT_SHADER_STAGE(DS, Domain, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT); +#endif +#if GPU_ALLOW_GEOMETRY_SHADERS INIT_SHADER_STAGE(GS, Geometry, VK_SHADER_STAGE_GEOMETRY_BIT); +#endif INIT_SHADER_STAGE(PS, Pixel, VK_SHADER_STAGE_FRAGMENT_BIT); #undef INIT_SHADER_STAGE _desc.pStages = _shaderStages; @@ -274,10 +280,13 @@ bool GPUPipelineStateVulkan::Init(const Description& desc) _descInputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; break; } +#if GPU_ALLOW_TESSELLATION_SHADERS if (desc.HS) _descInputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_PATCH_LIST; +#endif _desc.pInputAssemblyState = &_descInputAssembly; +#if GPU_ALLOW_TESSELLATION_SHADERS // Tessellation if (desc.HS) { @@ -285,6 +294,7 @@ bool GPUPipelineStateVulkan::Init(const Description& desc) _descTessellation.patchControlPoints = desc.HS->GetControlPointsCount(); _desc.pTessellationState = &_descTessellation; } +#endif // Viewport RenderToolsVulkan::ZeroStruct(_descViewport, VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO); diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUPipelineStateVulkan.h b/Source/Engine/GraphicsDevice/Vulkan/GPUPipelineStateVulkan.h index e3386064b..b8b326e83 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUPipelineStateVulkan.h +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUPipelineStateVulkan.h @@ -93,7 +93,9 @@ private: VkGraphicsPipelineCreateInfo _desc; VkPipelineShaderStageCreateInfo _shaderStages[ShaderStage_Count - 1]; VkPipelineInputAssemblyStateCreateInfo _descInputAssembly; +#if GPU_ALLOW_TESSELLATION_SHADERS VkPipelineTessellationStateCreateInfo _descTessellation; +#endif VkPipelineViewportStateCreateInfo _descViewport; VkPipelineDynamicStateCreateInfo _descDynamic; VkDynamicState _dynamicStates[3]; diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUShaderProgramVulkan.h b/Source/Engine/GraphicsDevice/Vulkan/GPUShaderProgramVulkan.h index 9c8649604..457b8998a 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUShaderProgramVulkan.h +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUShaderProgramVulkan.h @@ -107,6 +107,7 @@ public: } }; +#if GPU_ALLOW_TESSELLATION_SHADERS /// /// Hull Shader for Vulkan backend. /// @@ -146,7 +147,9 @@ public: { } }; +#endif +#if GPU_ALLOW_GEOMETRY_SHADERS /// /// Geometry Shader for Vulkan backend. /// @@ -165,6 +168,7 @@ public: { } }; +#endif /// /// Pixel Shader for Vulkan backend. diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUShaderVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUShaderVulkan.cpp index 45a3850da..b62324529 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUShaderVulkan.cpp +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUShaderVulkan.cpp @@ -194,6 +194,7 @@ GPUShaderProgram* GPUShaderVulkan::CreateGPUShaderProgram(ShaderStage type, cons break; } +#if GPU_ALLOW_TESSELLATION_SHADERS case ShaderStage::Hull: { int32 controlPointsCount; @@ -206,11 +207,21 @@ GPUShaderProgram* GPUShaderVulkan::CreateGPUShaderProgram(ShaderStage type, cons shader = New(_device, initializer, header->DescriptorInfo, shaderModule); break; } +#else + case ShaderStage::Hull: + { + int32 controlPointsCount; + stream.ReadInt32(&controlPointsCount); + break; + } +#endif +#if GPU_ALLOW_GEOMETRY_SHADERS case ShaderStage::Geometry: { shader = New(_device, initializer, header->DescriptorInfo, shaderModule); break; } +#endif case ShaderStage::Pixel: { shader = New(_device, initializer, header->DescriptorInfo, shaderModule); diff --git a/Source/Engine/Navigation/NavCrowd.cpp b/Source/Engine/Navigation/NavCrowd.cpp index f933ea12f..d9607489a 100644 --- a/Source/Engine/Navigation/NavCrowd.cpp +++ b/Source/Engine/Navigation/NavCrowd.cpp @@ -104,6 +104,15 @@ Vector3 NavCrowd::GetAgentPosition(int32 id) const return result; } +void NavCrowd::SetAgentPosition(int32 id, const Vector3& position) +{ + dtCrowdAgent* agent = _crowd->getEditableAgent(id); + if (agent) + { + *(Float3*)agent->npos = Float3(position); + } +} + Vector3 NavCrowd::GetAgentVelocity(int32 id) const { Vector3 result = Vector3::Zero; @@ -115,6 +124,15 @@ Vector3 NavCrowd::GetAgentVelocity(int32 id) const return result; } +void NavCrowd::SetAgentVelocity(int32 id, const Vector3& velocity) +{ + dtCrowdAgent* agent = _crowd->getEditableAgent(id); + if (agent) + { + *(Float3*)agent->vel = Float3(velocity); + } +} + void NavCrowd::SetAgentProperties(int32 id, const NavAgentProperties& properties) { dtCrowdAgentParams agentParams; diff --git a/Source/Engine/Navigation/NavCrowd.h b/Source/Engine/Navigation/NavCrowd.h index c69f789be..f92083734 100644 --- a/Source/Engine/Navigation/NavCrowd.h +++ b/Source/Engine/Navigation/NavCrowd.h @@ -63,6 +63,13 @@ public: /// The agent current position. API_FUNCTION() Vector3 GetAgentPosition(int32 id) const; + /// + /// Sets the agent current position. + /// + /// The agent ID. + /// The agent position. + API_FUNCTION() void SetAgentPosition(int32 id, const Vector3& position); + /// /// Gets the agent current velocity (direction * speed). /// @@ -70,6 +77,13 @@ public: /// The agent current velocity (direction * speed). API_FUNCTION() Vector3 GetAgentVelocity(int32 id) const; + /// + /// Sets the agent current velocity (direction * speed). + /// + /// The agent ID. + /// The agent velocity (direction * speed). + API_FUNCTION() void SetAgentVelocity(int32 id, const Vector3& velocity); + /// /// Updates the agent properties. /// diff --git a/Source/Engine/Networking/NetworkReplicationHierarchy.cpp b/Source/Engine/Networking/NetworkReplicationHierarchy.cpp index 03d7e61a6..224ee9f31 100644 --- a/Source/Engine/Networking/NetworkReplicationHierarchy.cpp +++ b/Source/Engine/Networking/NetworkReplicationHierarchy.cpp @@ -80,7 +80,16 @@ bool NetworkReplicationNode::DirtyObject(ScriptingObject* obj) if (index != -1) { NetworkReplicationHierarchyObject& e = Objects[index]; - e.ReplicationUpdatesLeft = 0; + if (e.ReplicationFPS < -ZeroTolerance) // < 0 + { + // Indicate for manual sync (see logic in Update) + e.ReplicationUpdatesLeft = 1; + } + else + { + // Replicate it next frame + e.ReplicationUpdatesLeft = 0; + } } return index != -1; } @@ -93,6 +102,12 @@ void NetworkReplicationNode::Update(NetworkReplicationHierarchyUpdateResult* res { if (obj.ReplicationFPS < -ZeroTolerance) // < 0 { + if (obj.ReplicationUpdatesLeft) + { + // Marked as dirty to sync manually + obj.ReplicationUpdatesLeft = 0; + result->AddObject(obj.Object); + } continue; } else if (obj.ReplicationFPS < ZeroTolerance) // == 0 @@ -167,7 +182,7 @@ void NetworkReplicationGridNode::AddObject(NetworkReplicationHierarchyObject obj cell->MinCullDistance = obj.CullDistance; } cell->Node->AddObject(obj); - _objectToCell[obj.Object] = coord; + _objectToCell[obj.Object.Get()] = coord; // Cache minimum culling distance for a whole cell to skip it at once cell->MinCullDistance = Math::Min(cell->MinCullDistance, obj.CullDistance); @@ -176,12 +191,10 @@ void NetworkReplicationGridNode::AddObject(NetworkReplicationHierarchyObject obj bool NetworkReplicationGridNode::RemoveObject(ScriptingObject* obj) { Int3 coord; - if (!_objectToCell.TryGet(obj, coord)) { return false; } - if (_children[coord].Node->RemoveObject(obj)) { _objectToCell.Remove(obj); @@ -195,12 +208,10 @@ bool NetworkReplicationGridNode::RemoveObject(ScriptingObject* obj) bool NetworkReplicationGridNode::GetObject(ScriptingObject* obj, NetworkReplicationHierarchyObject& result) { Int3 coord; - if (!_objectToCell.TryGet(obj, coord)) { return false; } - if (_children[coord].Node->GetObject(obj, result)) { return true; @@ -208,6 +219,16 @@ bool NetworkReplicationGridNode::GetObject(ScriptingObject* obj, NetworkReplicat return false; } +bool NetworkReplicationGridNode::DirtyObject(ScriptingObject* obj) +{ + Int3 coord; + if (_objectToCell.TryGet(obj, coord)) + { + return _children[coord].Node->DirtyObject(obj); + } + return NetworkReplicationNode::DirtyObject(obj); +} + void NetworkReplicationGridNode::Update(NetworkReplicationHierarchyUpdateResult* result) { CHECK(result); diff --git a/Source/Engine/Networking/NetworkReplicationHierarchy.h b/Source/Engine/Networking/NetworkReplicationHierarchy.h index ba2665622..78f9cad1f 100644 --- a/Source/Engine/Networking/NetworkReplicationHierarchy.h +++ b/Source/Engine/Networking/NetworkReplicationHierarchy.h @@ -20,11 +20,11 @@ API_STRUCT(NoDefault, Namespace = "FlaxEngine.Networking") struct FLAXENGINE_API // The object to replicate. API_FIELD() ScriptingObjectReference Object; - // The target amount of the replication updates per second (frequency of the replication). Constrained by NetworkManager::NetworkFPS. Use 0 for 'always relevant' object and less than 0 (eg. -1) for 'never relevant' objects that would only get synched on client join once. + // The target amount of the replication updates per second (frequency of the replication). Constrained by NetworkManager::NetworkFPS. Use 0 for 'always relevant' object and less than 0 (eg. -1) for 'never relevant' objects that would only get synced on client join once (or upon DirtyObject). API_FIELD() float ReplicationFPS = 60; // The minimum distance from the player to the object at which it can process replication. For example, players further away won't receive object data. Use 0 if unused. API_FIELD() float CullDistance = 15000; - // Runtime value for update frames left for the next replication of this object. Matches NetworkManager::NetworkFPS calculated from ReplicationFPS. + // Runtime value for update frames left for the next replication of this object. Matches NetworkManager::NetworkFPS calculated from ReplicationFPS. Set to 1 if ReplicationFPS less than 0 to indicate dirty object. API_FIELD(Attributes="HideInEditor") uint16 ReplicationUpdatesLeft = 0; FORCE_INLINE NetworkReplicationHierarchyObject(const ScriptingObjectReference& obj) @@ -257,6 +257,7 @@ public: void AddObject(NetworkReplicationHierarchyObject obj) override; bool RemoveObject(ScriptingObject* obj) override; bool GetObject(ScriptingObject* obj, NetworkReplicationHierarchyObject& result) override; + bool DirtyObject(ScriptingObject* obj) override; void Update(NetworkReplicationHierarchyUpdateResult* result) override; }; diff --git a/Source/Engine/Networking/NetworkReplicator.cpp b/Source/Engine/Networking/NetworkReplicator.cpp index 85e6bcdd3..5c8979d42 100644 --- a/Source/Engine/Networking/NetworkReplicator.cpp +++ b/Source/Engine/Networking/NetworkReplicator.cpp @@ -1203,7 +1203,7 @@ void NetworkReplicator::RemoveObject(ScriptingObject* obj) return; ScopeLock lock(ObjectsLock); const auto it = Objects.Find(obj->GetID()); - if (it != Objects.End()) + if (it == Objects.End()) return; // Remove object from the list diff --git a/Source/Engine/Platform/Android/AndroidDefines.h b/Source/Engine/Platform/Android/AndroidDefines.h index e6c2fa8f4..5cf857976 100644 --- a/Source/Engine/Platform/Android/AndroidDefines.h +++ b/Source/Engine/Platform/Android/AndroidDefines.h @@ -35,4 +35,7 @@ #define USE_MONO_AOT_MODE MONO_AOT_MODE_NONE +#define GPU_ALLOW_TESSELLATION_SHADERS 0 // Tess on mobile is not well supported +#define GPU_ALLOW_GEOMETRY_SHADERS 0 // Don't even try GS on mobile + #endif diff --git a/Source/Engine/Platform/Linux/LinuxPlatform.cpp b/Source/Engine/Platform/Linux/LinuxPlatform.cpp index f293521fd..1d3ccbd8c 100644 --- a/Source/Engine/Platform/Linux/LinuxPlatform.cpp +++ b/Source/Engine/Platform/Linux/LinuxPlatform.cpp @@ -2253,6 +2253,9 @@ bool LinuxPlatform::Init() } } + //Patch in numpad enter to normal enter, just like on windows. + KeyCodeMap[104] = KeyboardKeys::Return; + Input::Mouse = Impl::Mouse = New(); Input::Keyboard = Impl::Keyboard = New(); LinuxInput::Init(); diff --git a/Source/Engine/Platform/Mac/MacDefines.h b/Source/Engine/Platform/Mac/MacDefines.h index 456bd0b65..9c1188907 100644 --- a/Source/Engine/Platform/Mac/MacDefines.h +++ b/Source/Engine/Platform/Mac/MacDefines.h @@ -22,4 +22,7 @@ #define PLATFORM_HAS_HEADLESS_MODE 1 #define PLATFORM_DEBUG_BREAK __builtin_trap() +// MoltenVK has artifacts when using tess so disable it +#define GPU_ALLOW_TESSELLATION_SHADERS 0 + #endif diff --git a/Source/Engine/Platform/Win32/Win32FileSystem.h b/Source/Engine/Platform/Win32/Win32FileSystem.h index 0af67e4bc..42ac5f4a1 100644 --- a/Source/Engine/Platform/Win32/Win32FileSystem.h +++ b/Source/Engine/Platform/Win32/Win32FileSystem.h @@ -16,12 +16,12 @@ class FLAXENGINE_API Win32FileSystem : public FileSystemBase public: // Creates a new directory - // @param path Drectory path + // @param path Directory path // @returns True if cannot create directory, otherwise false static bool CreateDirectory(const StringView& path); // Deletes an existing directory - // @param path Drectory path + // @param path Directory path // @param deleteSubdirectories True if delete all subdirectories and files, otherwise false // @returns True if cannot delete directory, otherwise false static bool DeleteDirectory(const String& path, bool deleteContents = true); @@ -32,15 +32,15 @@ public: static bool DirectoryExists(const StringView& path); // Finds the names of files (including their paths) that match the specified search pattern in the specified directory, using a value to determine whether to search subdirectories - // @param results When this metod completes, this list contains list of all filenames that match the specified search pattern + // @param results When this method completes, this list contains list of all filenames that match the specified search pattern // @param path Path of the directory to search in it - // @param searchPattern Custo msearch pattern to use during that operation - // @param option Addidtional search options + // @param searchPattern Custom search pattern to use during that operation + // @param option Additional search options // @returns True if an error occurred, otherwise false static bool DirectoryGetFiles(Array& results, const String& path, const Char* searchPattern, DirectorySearchOption option = DirectorySearchOption::AllDirectories); // Finds the names of directories (including their paths) that are inside the specified directory - // @param results When this metod completes, this list contains list of all filenames that match the specified search pattern + // @param results When this method completes, this list contains list of all filenames that match the specified search pattern // @param directory Path of the directory to search in it // @returns True if an error occurred, otherwise false static bool GetChildDirectories(Array& results, const String& directory); diff --git a/Source/Engine/Platform/iOS/iOSDefines.h b/Source/Engine/Platform/iOS/iOSDefines.h index f3fd8f048..f9482acbc 100644 --- a/Source/Engine/Platform/iOS/iOSDefines.h +++ b/Source/Engine/Platform/iOS/iOSDefines.h @@ -18,4 +18,7 @@ #define USE_MONO_AOT 1 #define USE_MONO_AOT_MODE MONO_AOT_MODE_FULL +#define GPU_ALLOW_TESSELLATION_SHADERS 0 // MoltenVK has artifacts when using tess so disable it +#define GPU_ALLOW_GEOMETRY_SHADERS 0 // Don't even try GS on mobile + #endif diff --git a/Source/Engine/Renderer/ColorGradingPass.cpp b/Source/Engine/Renderer/ColorGradingPass.cpp index 92595ff86..7ac0da588 100644 --- a/Source/Engine/Renderer/ColorGradingPass.cpp +++ b/Source/Engine/Renderer/ColorGradingPass.cpp @@ -52,7 +52,9 @@ bool ColorGradingPass::Init() { // Detect if can use volume texture (3d) for a LUT (faster, requires geometry shader) const auto device = GPUDevice::Instance; +#if GPU_ALLOW_GEOMETRY_SHADERS _useVolumeTexture = device->Limits.HasGeometryShaders && device->Limits.HasVolumeTextureRendering; +#endif // Pick a proper LUT pixels format _lutFormat = PixelFormat::R10G10B10A2_UNorm; @@ -85,7 +87,7 @@ bool ColorGradingPass::Init() bool ColorGradingPass::setupResources() { // Wait for shader - if (!_shader->IsLoaded()) + if (!_shader || !_shader->IsLoaded()) return true; const auto shader = _shader->GetShader(); @@ -101,6 +103,7 @@ bool ColorGradingPass::setupResources() if (!_psLut.IsValid()) { StringAnsiView psName; +#if GPU_ALLOW_GEOMETRY_SHADERS if (_useVolumeTexture) { psDesc.VS = shader->GetVS("VS_WriteToSlice"); @@ -108,6 +111,7 @@ bool ColorGradingPass::setupResources() psName = "PS_Lut3D"; } else +#endif { psName = "PS_Lut2D"; } @@ -139,11 +143,13 @@ GPUTexture* ColorGradingPass::RenderLUT(RenderContext& renderContext) // For a 3D texture, the viewport is 16x16 (per slice), for a 2D texture, it's unwrapped to 256x16 const int32 LutSize = 32; // this must match value in shader (see ColorGrading.shader and PostProcessing.shader) GPUTextureDescription lutDesc; +#if GPU_ALLOW_GEOMETRY_SHADERS if (_useVolumeTexture) { lutDesc = GPUTextureDescription::New3D(LutSize, LutSize, LutSize, 1, _lutFormat); } else +#endif { lutDesc = GPUTextureDescription::New2D(LutSize * LutSize, LutSize, 1, _lutFormat); } @@ -192,6 +198,7 @@ GPUTexture* ColorGradingPass::RenderLUT(RenderContext& renderContext) context->BindSR(0, useLut ? colorGrading.LutTexture->GetTexture() : nullptr); // Draw +#if GPU_ALLOW_GEOMETRY_SHADERS if (_useVolumeTexture) { context->SetRenderTarget(lut->ViewVolume()); @@ -201,6 +208,7 @@ GPUTexture* ColorGradingPass::RenderLUT(RenderContext& renderContext) context->DrawFullscreenTriangle(numInstances); } else +#endif { context->SetRenderTarget(lut->View()); context->DrawFullscreenTriangle(); diff --git a/Source/Engine/Renderer/DepthOfFieldPass.cpp b/Source/Engine/Renderer/DepthOfFieldPass.cpp index 34ea05863..59a21094d 100644 --- a/Source/Engine/Renderer/DepthOfFieldPass.cpp +++ b/Source/Engine/Renderer/DepthOfFieldPass.cpp @@ -63,12 +63,14 @@ bool DepthOfFieldPass::Init() { _psDofDepthBlurGeneration = GPUDevice::Instance->CreatePipelineState(); _psDoNotGenerateBokeh = GPUDevice::Instance->CreatePipelineState(); +#if GPU_ALLOW_GEOMETRY_SHADERS if (_platformSupportsBokeh) { _psBokehGeneration = GPUDevice::Instance->CreatePipelineState(); _psBokeh = GPUDevice::Instance->CreatePipelineState(); _psBokehComposite = GPUDevice::Instance->CreatePipelineState(); } +#endif } // Load shaders @@ -137,6 +139,7 @@ bool DepthOfFieldPass::setupResources() if (_psDoNotGenerateBokeh->Init(psDesc)) return true; } +#if GPU_ALLOW_GEOMETRY_SHADERS if (_platformSupportsBokeh) { if (!_psBokehGeneration->IsValid()) @@ -171,6 +174,7 @@ bool DepthOfFieldPass::setupResources() if (_bokehIndirectArgsBuffer->Init(GPUBufferDescription::Argument(&indirectArgsBufferInitData, sizeof(indirectArgsBufferInitData)))) return true; } +#endif return false; } @@ -296,6 +300,7 @@ void DepthOfFieldPass::Render(RenderContext& renderContext, GPUTexture*& frame, auto dofFormat = renderContext.Buffers->GetOutputFormat(); tempDesc = GPUTextureDescription::New2D(dofWidth, dofHeight, dofFormat); +#if GPU_ALLOW_GEOMETRY_SHADERS // Do the bokeh point generation, or just do a copy if disabled bool isBokehGenerationEnabled = dofSettings.BokehEnabled && _platformSupportsBokeh && dofSettings.BokehBrightness > 0.0f && dofSettings.BokehSize > 0.0f; if (isBokehGenerationEnabled) @@ -329,6 +334,7 @@ void DepthOfFieldPass::Render(RenderContext& renderContext, GPUTexture*& frame, context->DrawFullscreenTriangle(); } else +#endif { // Generate bokeh points context->BindSR(0, frame); @@ -380,6 +386,7 @@ void DepthOfFieldPass::Render(RenderContext& renderContext, GPUTexture*& frame, context->ResetSR(); } +#if GPU_ALLOW_GEOMETRY_SHADERS // Render the bokeh points if (isBokehGenerationEnabled) { @@ -418,6 +425,7 @@ void DepthOfFieldPass::Render(RenderContext& renderContext, GPUTexture*& frame, RenderTargetPool::Release(bokehTarget); Swap(frame, tmp); } +#endif RenderTargetPool::Release(depthBlurTarget); } diff --git a/Source/Engine/Renderer/EyeAdaptationPass.cpp b/Source/Engine/Renderer/EyeAdaptationPass.cpp index a43a87d72..e44189454 100644 --- a/Source/Engine/Renderer/EyeAdaptationPass.cpp +++ b/Source/Engine/Renderer/EyeAdaptationPass.cpp @@ -46,7 +46,6 @@ void EyeAdaptationPass::Render(RenderContext& renderContext, GPUTexture* colorBu renderContext.Buffers->LastEyeAdaptationTime = 0.0f; if ((view.Flags & ViewFlags::EyeAdaptation) == ViewFlags::None || settings.Mode == EyeAdaptationMode::None || checkIfSkipPass()) return; - PROFILE_GPU_CPU("Eye Adaptation"); // Setup constants @@ -218,14 +217,15 @@ String EyeAdaptationPass::ToString() const bool EyeAdaptationPass::Init() { - _canUseHistogram = GPUDevice::Instance->Limits.HasCompute; + auto device = GPUDevice::Instance; + _canUseHistogram = device->Limits.HasCompute; // Create pipeline states - _psManual = GPUDevice::Instance->CreatePipelineState(); - _psLuminanceMap = GPUDevice::Instance->CreatePipelineState(); - _psBlendLuminance = GPUDevice::Instance->CreatePipelineState(); - _psApplyLuminance = GPUDevice::Instance->CreatePipelineState(); - _psHistogram = GPUDevice::Instance->CreatePipelineState(); + _psManual = device->CreatePipelineState(); + _psLuminanceMap = device->CreatePipelineState(); + _psBlendLuminance = device->CreatePipelineState(); + _psApplyLuminance = device->CreatePipelineState(); + _psHistogram = device->CreatePipelineState(); // Load shaders _shader = Content::LoadAsyncInternal(TEXT("Shaders/EyeAdaptation")); diff --git a/Source/Engine/Renderer/HistogramPass.cpp b/Source/Engine/Renderer/HistogramPass.cpp index 7db55d655..44e31a094 100644 --- a/Source/Engine/Renderer/HistogramPass.cpp +++ b/Source/Engine/Renderer/HistogramPass.cpp @@ -29,7 +29,6 @@ GPUBuffer* HistogramPass::Render(RenderContext& renderContext, GPUTexture* color auto context = device->GetMainContext(); if (checkIfSkipPass() || !_isSupported) return nullptr; - PROFILE_GPU_CPU("Histogram"); // Setup constants diff --git a/Source/Engine/Streaming/StreamingHandlers.cpp b/Source/Engine/Streaming/StreamingHandlers.cpp index 44ea60774..0b10fba1b 100644 --- a/Source/Engine/Streaming/StreamingHandlers.cpp +++ b/Source/Engine/Streaming/StreamingHandlers.cpp @@ -59,7 +59,7 @@ int32 TexturesStreamingHandler::CalculateResidency(StreamableResource* resource, if (mipLevels > 0 && mipLevels < texture._minMipCountBlockCompressed && texture._isBlockCompressed) { - // Block compressed textures require minimum size of 4 + // Block compressed textures require minimum size of block size (eg. 4 for BC formats) mipLevels = texture._minMipCountBlockCompressed; } diff --git a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Material.cpp b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Material.cpp index 508417895..66d24d4f3 100644 --- a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Material.cpp +++ b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Material.cpp @@ -421,15 +421,31 @@ void MaterialGenerator::ProcessGroupMaterial(Box* box, Node* node, Value& value) // DDX case 30: { - const auto inValue = tryGetValue(node->GetBox(0), 0, Value::Zero); - value = writeLocal(inValue.Type, String::Format(TEXT("ddx({0})"), inValue.Value), node); + if (_treeType == MaterialTreeType::PixelShader) + { + const auto inValue = tryGetValue(node->GetBox(0), 0, Value::Zero); + value = writeLocal(inValue.Type, String::Format(TEXT("ddx({0})"), inValue.Value), node); + } + else + { + // No derivatives support in VS/DS + value = Value::Zero; + } break; } // DDY case 31: { - const auto inValue = tryGetValue(node->GetBox(0), 0, Value::Zero); - value = writeLocal(inValue.Type, String::Format(TEXT("ddy({0})"), inValue.Value), node); + if (_treeType == MaterialTreeType::PixelShader) + { + const auto inValue = tryGetValue(node->GetBox(0), 0, Value::Zero); + value = writeLocal(inValue.Type, String::Format(TEXT("ddy({0})"), inValue.Value), node); + } + else + { + // No derivatives support in VS/DS + value = Value::Zero; + } break; } // Sign diff --git a/Source/Engine/Tools/ModelTool/ModelTool.h b/Source/Engine/Tools/ModelTool/ModelTool.h index f70584681..96d1ae6c0 100644 --- a/Source/Engine/Tools/ModelTool/ModelTool.h +++ b/Source/Engine/Tools/ModelTool/ModelTool.h @@ -196,7 +196,7 @@ public: String CollisionMeshesPrefix = TEXT(""); // The type of collision that should be generated if the mesh has a collision prefix specified. API_FIELD(Attributes = "EditorOrder(105), EditorDisplay(\"Geometry\"), VisibleIf(nameof(ShowGeometry))") - CollisionDataType CollisionType = CollisionDataType::TriangleMesh; + CollisionDataType CollisionType = CollisionDataType::ConvexMesh; public: // Transform diff --git a/Source/Engine/UI/UICanvas.cs b/Source/Engine/UI/UICanvas.cs index db78e428f..0ddac70e1 100644 --- a/Source/Engine/UI/UICanvas.cs +++ b/Source/Engine/UI/UICanvas.cs @@ -73,6 +73,7 @@ namespace FlaxEngine if (renderContext.View.Frustum.Contains(bounds.GetBoundingBox()) == ContainmentType.Disjoint) return; + Profiler.BeginEvent("UI Canvas"); Profiler.BeginEventGPU("UI Canvas"); // Calculate rendering matrix (world*view*projection) @@ -90,6 +91,7 @@ namespace FlaxEngine Render2D.CallDrawing(Canvas.GUI, context, input, depthBuffer, ref viewProjectionMatrix); Render2D.Features = features; + Profiler.EndEvent(); Profiler.EndEventGPU(); } } diff --git a/Source/Tools/Flax.Build/Deploy/Deployment.Editor.cs b/Source/Tools/Flax.Build/Deploy/Deployment.Editor.cs index ee682576b..98a9ef530 100644 --- a/Source/Tools/Flax.Build/Deploy/Deployment.Editor.cs +++ b/Source/Tools/Flax.Build/Deploy/Deployment.Editor.cs @@ -345,12 +345,12 @@ namespace Flax.Deploy // Optimize package size Utilities.Run("strip", "FlaxEditor", null, dst, Utilities.RunOptions.None); - Utilities.Run("strip", "FlaxEditor.dylib", null, dst, Utilities.RunOptions.None); + Utilities.Run("strip", "FlaxEngine.dylib", null, dst, Utilities.RunOptions.None); Utilities.Run("strip", "libMoltenVK.dylib", null, dst, Utilities.RunOptions.None); // Sign binaries CodeSign(Path.Combine(dst, "FlaxEditor")); - CodeSign(Path.Combine(dst, "FlaxEditor.dylib")); + CodeSign(Path.Combine(dst, "FlaxEngine.dylib")); CodeSign(Path.Combine(dst, "libMoltenVK.dylib")); } } diff --git a/Source/Tools/Flax.Build/Deploy/VCEnvironment.cs b/Source/Tools/Flax.Build/Deploy/VCEnvironment.cs index f75c89c8d..4aa5cc060 100644 --- a/Source/Tools/Flax.Build/Deploy/VCEnvironment.cs +++ b/Source/Tools/Flax.Build/Deploy/VCEnvironment.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; using System.IO; -using System.Linq; using Flax.Build; using Flax.Build.Platforms; using Flax.Build.Projects.VisualStudio; @@ -288,10 +287,25 @@ namespace Flax.Deploy var sdks = WindowsPlatformBase.GetSDKs(); if (sdks.Count == 0) throw new Exception("No Windows SDK found. Cannot sign file."); - var sdkKeys = sdks.Keys.ToList(); - sdkKeys.Sort(); - var sdk = sdks[sdkKeys.Last()]; - var signtool = Path.Combine(sdk, "bin", "x64", "signtool.exe"); + var signtool = string.Empty; + foreach (var e in sdks) + { + try + { + var sdk = e.Value; + signtool = Path.Combine(sdk, "bin", "x64", "signtool.exe"); + if (File.Exists(signtool)) + break; + var ver = WindowsPlatformBase.GetSDKVersion(e.Key); + signtool = Path.Combine(sdk, "bin", ver.ToString(4), "x64", "signtool.exe"); + if (File.Exists(signtool)) + break; + } + catch + { + // Ignore version formatting exception + } + } var cmdLine = string.Format("sign /debug /f \"{0}\" /p \"{1}\" /tr http://timestamp.comodoca.com /td sha256 /fd sha256 \"{2}\"", certificatePath, certificatePass, file); Utilities.Run(signtool, cmdLine, null, null, Utilities.RunOptions.Default | Utilities.RunOptions.ThrowExceptionOnError); } diff --git a/Source/Tools/Flax.Build/Platforms/Windows/WindowsToolchainBase.cs b/Source/Tools/Flax.Build/Platforms/Windows/WindowsToolchainBase.cs index c31a63cca..c1cdcb0ee 100644 --- a/Source/Tools/Flax.Build/Platforms/Windows/WindowsToolchainBase.cs +++ b/Source/Tools/Flax.Build/Platforms/Windows/WindowsToolchainBase.cs @@ -484,12 +484,6 @@ namespace Flax.Build.Platforms // Remove unreferenced COMDAT commonArgs.Add("/Zc:inline"); - // Favor Small Code, Favor Fast Code - if (compileEnvironment.FavorSizeOrSpeed == FavorSizeOrSpeed.FastCode) - commonArgs.Add("/Ot"); - else if (compileEnvironment.FavorSizeOrSpeed == FavorSizeOrSpeed.SmallCode) - commonArgs.Add("/Os"); - // Run-Time Error Checks if (compileEnvironment.RuntimeChecks && !compileEnvironment.CompileAsWinRT) commonArgs.Add("/RTC1"); @@ -510,10 +504,16 @@ namespace Flax.Build.Platforms commonArgs.Add("/Zo"); } + // Favor Small Code, Favor Fast Code + if (compileEnvironment.FavorSizeOrSpeed == FavorSizeOrSpeed.FastCode) + commonArgs.Add("/Ot"); + else if (compileEnvironment.FavorSizeOrSpeed == FavorSizeOrSpeed.SmallCode) + commonArgs.Add("/Os"); if (compileEnvironment.Optimization) { // Enable Most Speed Optimizations - commonArgs.Add("/Ox"); + // Commented out due to /Og causing slow build times without /GL in development builds + //commonArgs.Add("/Ox"); // Generate Intrinsic Functions commonArgs.Add("/Oi"); @@ -523,6 +523,9 @@ namespace Flax.Build.Platforms if (compileEnvironment.WholeProgramOptimization) { + // Enable Most Speed Optimizations + commonArgs.Add("/Ox"); + // Whole Program Optimization commonArgs.Add("/GL"); } @@ -908,7 +911,7 @@ namespace Flax.Build.Platforms } else { - args.Add("/DEBUG"); + args.Add("/DEBUG"); // Same as /DEBUG:FULL } // Use Program Database