From bf66aaa497239f960a092eeee7db134b19324eb5 Mon Sep 17 00:00:00 2001 From: Ben Marsh Date: Sun, 1 May 2016 17:37:41 -0400 Subject: [PATCH] Copying //UE4/Release-Staging-4.12 to //UE4/Dev-Main (Source: //UE4/Release-4.12 @ 2955635) ========================== MAJOR FEATURES + CHANGES ========================== Change 2955635 on 2016/04/26 by Max.Chen Sequencer: Fix filtering so that folders that contain filtered nodes will also appear. #jira UE-28213 Change 2955617 on 2016/04/25 by Dmitriy.Dyomin Better fix for: Post processing rendering artifacts Nexus 6 this device on Android 5.0.1 does not support BGRA8888 texture as a color attachment #jira: UE-24067 Change 2955522 on 2016/04/25 by Max.Chen Sequencer: Fix crash when resolving object guid and context is null. #jira UE-29916 Change 2955504 on 2016/04/25 by Alexis.Matte #jira UE-29926 Fix build error for SplineComponent. I just move variable under #if !UE_BUILD_SHIPPING instead #if WITH_EDITORONLY_DATA to fix all build flavor, please feel free to adjust according to what the initial fix was suppose to do. Change 2955500 on 2016/04/25 by Dan.Oconnor Integration of 2955445 from Dev-BP #jira UE-29012 Change 2955234 on 2016/04/25 by Lina.Halper Fixed tool tip of twist node #jira : UE-29907 Change 2955211 on 2016/04/25 by Ben.Marsh Exclude all plugins which aren't required for a project (ie. don't have any content or modules for the current target) from its target receipt. Prevents dependencies on .uplugin files whose dependencies are otherwise compiled out. Re-enable PS4Media plugin by default. #jira UE-29842 Change 2955155 on 2016/04/25 by Jamie.Dale Fixed an issue where text committed via a focus loss might not display the correct text if it was changed during commit #jira UE-28756 Change 2955144 on 2016/04/25 by Jamie.Dale Fixed a case where editable text controls would fail to select their text when focused There was an order of operations issue between the options to select all text and move the cursor to the end of the document, which caused the cursor move to happen after the select all, and undo the selection. The order of these operations has now been flipped. #jira UE-29818 #jira UE-29772 Change 2955136 on 2016/04/25 by Chad.Taylor Merging to 4.12: Morpheus latency fix. Late update tracking frame was getting unnecessarily buffered an extra frame on the RHI thread. Removed buffering and the issue is fixed. #jira UE-22581 Change 2955134 on 2016/04/25 by Lina.Halper Removed code that blocks moving actor when they don't have physics asset #jira : UE-29796 #code review: Benn.Gallagher Change 2955130 on 2016/04/25 by Zak.Middleton #ue4 - (4.12) Don't reject low distance MTD, it could cause us to not process some valid overlaps. (copy of 2955001 in Main) #jira UE-29531 #lockdown Nick.Penwarden Change 2955098 on 2016/04/25 by Marc.Audy Don't spawn a child actor on the client if the server is going to have created one and be replicating it to the client #jira UE-7539 Change 2955049 on 2016/04/25 by Richard.TalbotWatkin Changes to how SplineComponents debug render. Added a SetDrawDebug method to control whether a spline is rendered. Also extended the facility to non-editor builds. #jira UE-29753 - Add ability to display a SplineComponent in-game Change 2955040 on 2016/04/25 by Chris.Gagnon Fixed Initializer Order Warning in hot reload ctor. #jira UE-28811, UE-28960 Change 2954995 on 2016/04/25 by Marc.Audy Make USceneComponent::Pre/PostNetReceive and PostRepNotifies protected instead of private so that subclasses can implement replication behaviors #jira UE-29909 Change 2954970 on 2016/04/25 by Peter.Sauerbrei fix for openwrite with O_APPEND flag #jira UE-28417 Change 2954917 on 2016/04/25 by Chris.Gagnon Moved a desired change from Main to 4.12 Added input settings to: - control if the viewport locks the mouse on acquire capture. - control if the viewport acquires capture on the application launch (first window activate). #jira UE-28811, UE-28960 parity with 4.11 (UE-28811, UE-28960 would be reintroduced without this) Change 2954908 on 2016/04/25 by Alexis.Matte #jira UE-29478 Prevent modal dialog to use 100% of a core Change 2954888 on 2016/04/25 by Marcus.Wassmer Fix compile issue with chinese locale #jira UE-29708 Change 2954813 on 2016/04/25 by Lina.Halper Fix when not re-validating the correct asset #jira : UE-29789 #code review: Martin.Wilson Change 2954810 on 2016/04/25 by mason.seay Updated map to improve coverage #jira UE-29618 Change 2954785 on 2016/04/25 by Max.Chen Sequencer: Always spawn sequencer spawnables. Disregard collision settings. #jira UE-29825 Change 2954781 on 2016/04/25 by mason.seay Test map for Audio Occlusion trace channels #jira UE-29618 Change 2954684 on 2016/04/25 by Marc.Audy Add GetIsReplicated accessor to AActor Deprecate specific GameplayAbility class implementations that was exposing bReplicates #jira UE-29897 Change 2954675 on 2016/04/25 by Alexis.Matte #jira UE-25430 Light Intensity value in FBX is a ratio. So I just multiply the default intensity value by the ratio to have something closer to the look in the DCCs Change 2954669 on 2016/04/25 by Alexis.Matte #jira UE-29507 Import of rigid mesh animation is broken Change 2954579 on 2016/04/25 by Ben.Marsh Temporarily stop the PS4Media plugin being enabled by default, so the UE4Game built for the binary release doesn't depend on it. Will implement whitelist/blacklist for platforms later. #jira UE-29842 Change 2954556 on 2016/04/25 by Taizyd.Korambayil #jira UE-29877 Setup ThirdPersonCharacter based on correct Code Class Change 2954552 on 2016/04/25 by Taizyd.Korambayil #jira UE-29877 Deleting BP class Change 2954498 on 2016/04/25 by Ryan.Gerleve Fix for remote player controllers reporting that they're actually local player controllers after a seamless travel on the server. Transition actors to the new level in a second pass after non-transitioning actors are handled. #jira UE-29213 Change 2954446 on 2016/04/25 by Max.Chen Sequencer: Fixed spawning actors with instance or multiple owned components - Also fixed issue where recorded actors were sometimes set as transient, meaning they didn't get saved #jira UE-29774, UE-29859 Change 2954430 on 2016/04/25 by Marc.Audy Don't schedule a tick function with a tick interval that was disabled while it was pending rescheduling #jira UE-29118 #jira UE-29747 Change 2954292 on 2016/04/25 by Richard.TalbotWatkin Replicated from //UE4/Dev-Editor CL 2946363 (by Frank.Fella) CurveEditorViewportClient - Bounds check when box selecting. Prevents crashing when the box is outside the viewport. #jira UE-29265 - Crash when drag selecting curve keys in matinee Change 2954262 on 2016/04/25 by Graeme.Thornton Fixed a editor crash when destroying linkers half way through a package EndLoad #jira UE-29437 Change 2954239 on 2016/04/25 by Marc.Audy Fix error message #jira UE-00000 Change 2954177 on 2016/04/25 by Dmitriy.Dyomin Fixed: Hidden surface removal is not enabled on PowerVR Android devices #jira UE-29871 Change 2954026 on 2016/04/24 by Josh.Adams [Somehow most files got unchecked in my previous checkin, grr] - ProtoStar content/config updates (enabled TAA in the levels, disabled es2 shaders, hides the Unbuilt lighting warning on Android) #lockdown nick.penwarden #jira UE-29863 Change 2954025 on 2016/04/24 by Josh.Adams - ProtoStar content/config updates (enabled TAA in the levels, disabled es2 shaders, hides the Unbuilt lighting warning on Android) #lockdown nick.penwarden #jira UE-29863 Change 2953946 on 2016/04/24 by Max.Chen Sequencer: Fix crash on undo of a sub section. #jira UE-29856 Change 2953898 on 2016/04/23 by mitchell.wilson #jira UE-29618 Adding subscene_001 sequence for nonlinear workflow testing Change 2953859 on 2016/04/23 by Maciej.Mroz Merged from Dev-Blueprints 2953858 #jira UE-29790 Editor crashes when opening KiteDemo Change 2953764 on 2016/04/23 by Max.Chen Sequencer: Remove "Experimental" tag on the Level Sequence Actor #jira UETOOl-625 Change 2953763 on 2016/04/23 by Max.Chen Cinematics: Change text to "Edit Existing Cinematics" #jira UE-29102 Change 2953762 on 2016/04/23 by Max.Chen Sequencer: Follow up time slider hit testing fix. Don't hit test the selection range if it's empty. This was causing false positives when hovering close to the ranges. #jira UE-29658 Change 2953652 on 2016/04/22 by Rolando.Caloca UE4.12 - vk - Workaround driver bugs wrt texture format caps #jira UE-28140 Change 2953596 on 2016/04/22 by Marcus.Wassmer #jira UE-20276 Merging dual normal clearcoat shading model. 2863683 2871229 2876362 2876573 2884007 2901595 Change 2953594 on 2016/04/22 by Chris.Babcock Disable crash handler for VulkanRHI on Android to prevent sig11 on loading driver #jira UE-29851 #ue4 #android Change 2953520 on 2016/04/22 by Rolando.Caloca UE4.12 - vk - Enable deferred resource deletion - Added one resource heap per memory type - Improved DumpMemory() - Added ensures for missing format features #jira UE-28140 Change 2953459 on 2016/04/22 by Taizyd.Korambayil #jira UE-29748 Resaved Maps to Fix EC Build Warnings #jira UE-29744 Change 2953448 on 2016/04/22 by Ryan.Gerleve Fix Mac/Linux compile. #jira UE-29545 Change 2953311 on 2016/04/22 by Ryan.Gerleve Fix for infinite hang when loading a replay from within an actor tick while demo.AsyncLoadWorld is false. LoadMap for the replay is now deferred using the existing PendingNetGame mechanism. Added virtual UPendingNetGame::LoadMapCompleted function so that the base PendingNetGame and DemoPendingNetGame can have different behavior. To keep things simpler, also parse all replay metadata and streaming levels after the LoadMap call. #jira UE-29545 Change 2953219 on 2016/04/22 by mason.seay Test map for show collision features #jira UE-29618 Change 2953199 on 2016/04/22 by Phillip.Kavan [UE-29449] Fix InitProperties() optimization for Blueprint class instances when array property values differ in size. change summary: - improved UBlueprintGeneratedClass::BuildCustomArrayPropertyListForPostConstruction() by continuing to emit only delta entries for array values that exceed the default array value's size; previously we emitted a NULL in this case to signal a need to initialize all remaining array values in InitProperties(), even if they didn't differ from the default value of the inner property (which in most cases would already have been set at construction time, and thus potentially incurred a redundant copy iteration for each entry) - modified FObjectInitializer::InitArrayPropertyFromCustomList() to no longer reset the array value on the instance prior to initialization - added code to properly resize the array on the instance prior to initialization (if it differs in size from the default array value) - removed code that handled a NULL property value in the custom property list stream (this is no longer necessary, see above) - modified FObjectInitializer::InitProperties() to restore the post-construction optimization for Blueprint class instances (back to being enabled by default) #jira UE-29449 Change 2953195 on 2016/04/22 by Max.Chen Sequencer: Fix crash in actor reference track in the cached guid to actor map. #jira UE-27523 Change 2953124 on 2016/04/22 by Rolando.Caloca UE4.12 - vk - Increase temp frame buffer #jira UE-28140 Change 2953121 on 2016/04/22 by Chris.Babcock Rebuilt lighting for all levels #jira UE-29809 Change 2953073 on 2016/04/22 by mason.seay Test assets for notifies in animation composites and montages #jira UE-29618 Change 2952960 on 2016/04/22 by Richard.TalbotWatkin Changed eye dropper operation so that LMB click selects a color, and pressing Esc cancels the selection and restores the old color. #jira UE-28410 - Eye dropper selects color without clicking Change 2952934 on 2016/04/22 by Allan.Bentham Ensure pool's refractive index >= 1 #jira UE-29777 Change 2952881 on 2016/04/22 by Jamie.Dale Better fix for UE-28560 that doesn't regress thumbnail rendering We now just silence the warning if dealing with an inactive world. #jira UE-28560 Change 2952867 on 2016/04/22 by Thomas.Sarkanen Fix issues with matinee-controlled anim instances Regression caused by us no longer saving off the anim sequence between updates. #jira UE-29812 - Protostar Neutrino spawns but does not Animate or move. Change 2952826 on 2016/04/22 by Maciej.Mroz Merged from Dev-Blueprints 2952820 #jira UE-28895 Nativizing a blueprint project causes the next non-nativizing package attempt to fail Change 2952819 on 2016/04/22 by Josh.Adams - Fixed crash in a Vulkan shader printout #lockdown nick.penwarden #jira UE-29820 Change 2952817 on 2016/04/22 by Rolando.Caloca UE4.12 - vk - Revert back to simple layouts #jira UE-28140 Change 2952792 on 2016/04/22 by Jamie.Dale Removed some code that caused worlds loaded by the Content Browser to be initialized before they were ready Supposedly this code existed for world thumbnail rendering, however only the active editor world generates a thumbnail, so initializing other worlds wasn't having any effect and thumbnails look identical to before. #jira UE-28560 Change 2952783 on 2016/04/22 by Taizyd.Korambayil #jira UE-28477 Resaved Flying Template Map Change 2952767 on 2016/04/22 by Taizyd.Korambayil #jira UE-29736 Resaved Map to Fix EC Warnings Change 2952762 on 2016/04/22 by Allan.Bentham Update reflection capture to contain only room5 content. #jira UE-29777 Change 2952749 on 2016/04/22 by Taizyd.Korambayil #jira UE-29740 Resaved Material and Map to Fix Empty Engine Version Error Change 2952688 on 2016/04/22 by Martin.Wilson Fix for BP notifies not displaying when they derive from an abstract base class #jira UE-28556 Change 2952685 on 2016/04/22 by Thomas.Sarkanen Fix CIS for non-editor builds #jira UE-29308 - Fix crash from GC-ed animation asset Change 2952664 on 2016/04/22 by Thomas.Sarkanen Made up/down behaviour for console history consistent and reverted to old ordering by default Pressing up or down now brings up history. Sorting can now be optionally bottom-to-top or top-to-bottom. Default behaviour is preserved to what it was before the recent changes. #jira UE-29595 - Console autocomplete behavior is non-intuitive / frustrating Change 2952655 on 2016/04/22 by Jamie.Dale Changed the class filter to use an expression evaluator This makes it consistent with the other filters in the editor #jira UE-29811 Change 2952647 on 2016/04/22 by Allan.Bentham Back out changelist 2951539 #jira UE-29777 Change 2952618 on 2016/04/22 by Benn.Gallagher Fixed naming error in rotation multiplier node #jira UE-29583 Change 2952612 on 2016/04/22 by Thomas.Sarkanen Fix garbage collection and undo/redo issues with anim instance proxy UObject-based properties are now cached each update on the proxy and nulled-out outside of evaluate/update phases. Moved some initialization code for CurrentAsset/CurrentVertexAnim from the proxy back to the instance (as its is encapsulated there now). #jira UE-29308 - Fix crash from GC-ed animation asset Change 2952608 on 2016/04/22 by Richard.TalbotWatkin Changed 'Recently Used Levels' and 'Favorite Levels' to hold long package names instead of absolute paths. This means they are now project-relative and will remain valid even if the project location changes. #jira UE-29731 - Editor map recent files are not project relative, leading to missing links when moving projects. Change 2952599 on 2016/04/22 by Dmitriy.Dyomin Disabled vulkan pipeline cache as it causes rendering artifacts right now #jira UE-29807 Change 2952540 on 2016/04/22 by Maciej.Mroz #jira UE-29787 Obsolete nativized files are never removed merged from Dev-Blueprints 2952531 Change 2952372 on 2016/04/21 by Josh.Adams - Fixed Vk memory allocations when reusing free pages #lockdown nick.penwarden #jira ue-29802 Change 2952350 on 2016/04/21 by Eric.Newman Added support for UEReleaseTesting backends to Orion and Ocean #jira op-3640 Change 2952140 on 2016/04/21 by Dan.Oconnor Demoted back to warning to fix regressions in content examples, in main we've added the ability to elevate warnings to errors, but no reason to rush that feature into 4.12 #jira UE-28971 Change 2952135 on 2016/04/21 by Jeff.Farris Fixed issue in PlayerCameraManager where the priority-based sorting of CameraModifiers wasn't sorting properly. Manual re-implementation of CL 2948123 in 4.12 branch. #jira UE-29634 Change 2952121 on 2016/04/21 by Lee.Clark PS4 - 4.12 - Fix staging and deploying of system prxs #jira UE-29801 Change 2952120 on 2016/04/21 by Rolando.Caloca UE4.12 - vk - Move descriptor allocation to BSS #jira UE-21840 Change 2952027 on 2016/04/21 by Rolando.Caloca UE4.12 - vk - Fix descriptor sets lifetimes - Fix crash with null texture #jira UE-28140 Change 2951890 on 2016/04/21 by Eric.Newman Updating locked common dependencies for OrionService #jira OP-3640 Change 2951863 on 2016/04/21 by Eric.Newman Updating locked dependencies for UE 4.12 OrionService #jira OP-3640 Change 2951852 on 2016/04/21 by Owen.Stupka Fixed meteors destruct location #jira UE-29714 Change 2951739 on 2016/04/21 by Max.Chen Sequencer: Follow up for integral keys. #jira UE-29791 Change 2951717 on 2016/04/21 by Rolando.Caloca UE4.12 - Fix shader platform names #jira UE-28140 Change 2951714 on 2016/04/21 by Max.Chen Sequencer: Fix setting a key if it already exists at the current time. #jira UE-29791 Change 2951708 on 2016/04/21 by Rolando.Caloca UE4.12 - vk - Separate upload cmd buffer #jira UE-28140 Change 2951653 on 2016/04/21 by Marc.Audy If a child actor component is destroyed during garbage collection, do not rename, instead clear the caching mechanisms so that a new name is chosen if a new child is created in the future Remove now unused bRenameRequired parameter #jira UE-29612 Change 2951619 on 2016/04/21 by Chris.Babcock Move bCreateRenderStateForHiddenComponents out of WITH_EDITOR #jira UE-29786 #ue4 Change 2951603 on 2016/04/21 by Cody.Albert #jira UE-29785 Revert Github readme page back to original Change 2951599 on 2016/04/21 by Ryan.Gerleve Fix assert when attempting to record a replay when the map has a placed actor that writes replay external data (such as ACharacter) #jira UE-29778 Change 2951558 on 2016/04/21 by Chris.Babcock Always rename destroyed child actor #jira UE-29709 #ue4 Change 2951552 on 2016/04/21 by James.Golding Remove old code for handling 'show collision' in game, uses same method as editor now, fixes hidden meshes showing up in game when doing 'show collision' #jira UE-29303 Change 2951539 on 2016/04/21 by Allan.Bentham Use screenuv for distortion with ES2/31. #jira UE-29777 Change 2951535 on 2016/04/21 by Max.Chen We need to test if the hmd is enabled if it exists. Otherwise, this will return true even if we aren't rendering in stereo if there's an hmd plugin loaded. #jira UE-29711 Change 2951521 on 2016/04/21 by Taizyd.Korambayil #jira UE-29746 Replaced Deprecated Time Handler node in GameLevel_GM Change 2951492 on 2016/04/21 by Jeremiah.Waldron Fix for Android IAP information reporting back incorrectly. #jira UE-29776 Change 2951486 on 2016/04/21 by Taizyd.Korambayil #jira UE-29741 Updated Infiltrator Demo Project to open with the correct Map Change 2951450 on 2016/04/21 by Gareth.Martin Fix non-editor build #jira UE-16525 Change 2951380 on 2016/04/21 by Gareth.Martin Fix Landscape layer blend nodes not updating connections correctly when an input is changed from weight/alpha (one input) to height blend (two inputs) or vice-versa #jira UE-16525 Change 2951357 on 2016/04/21 by Richard.TalbotWatkin Fixed a crash when pushing a new menu leads to a window activation change which would result in the old root menu being dismissed. #jira UE-27981 - [CrashReport] Crash When Attempting to Select Variable Type After Clearing the Name Field Change 2951352 on 2016/04/21 by Richard.TalbotWatkin Added slider bar thickness as a new property in FSliderStyle. #jira UE-19173 - SSlider is not fully stylable Change 2951344 on 2016/04/21 by Gareth.Martin Fix bounds calculation for landscape splines that was causing the first landscape spline point to be invisible and later points to flicker. - Also fixes landscape spline lines not showing up on a flat landscape #jira UE-25114 Change 2951326 on 2016/04/21 by Taizyd.Korambayil #jira UE-28477 Resaving Maps Change 2951271 on 2016/04/21 by Jamie.Dale Fixed a crash when pasting a path containing a class into the asset view of the Content Browser #jira UE-29616 Change 2951237 on 2016/04/21 by Jack.Porter Fix black screen on PC due to planar reflections #jira UE-29664 Change 2951184 on 2016/04/21 by Jamie.Dale Fixed crash in FCurveStructCustomization when no objects were selected for editing #jira UE-29638 Change 2951177 on 2016/04/21 by Ben.Marsh Fix hot reload from IDE failing when project is up to date. UBT returns an exit code of 2, and any non-zero exit code is treated as an error by Visual Studio. Build.bat was not correctly forwarding on the exit code at all prior to CL 2790858. #jira UE-29757 Change 2951171 on 2016/04/21 by Matthew.Griffin Fixed issue with Rebuild not working when installed in Program Files (x86) The brackets seem to cause lots of problems in combination with the if/else ones #jira UE-29648 Change 2951163 on 2016/04/21 by Jamie.Dale Changed the text customization to use the property handle functions to get/set the text value That ensures that it both transacts and notifies correctly. Added new functions to deal with multiple objects selection efficiently with the existing IEditableTextProperty API: - FPropertyHandleBase::SetPerObjectValue - FPropertyHandleBase::GetPerObjectValue - FPropertyHandleBase::GetNumPerObjectValues These replace the need to cache the raw pointers. #jira UE-20223 Change 2951103 on 2016/04/21 by Thomas.Sarkanen Un-deprecated blueprint functions for attachment/detachment Renamed functions to (Deprecated). Hid functions in the BP context menu so new ones cant be added. #jira UE-23216 - "Snap to Target, Keep World Scale" when attaching doesn't work properly if parent is scaled. Change 2951101 on 2016/04/21 by Allan.Bentham Enable mobile HQ DoF #jira UE-29765 Change 2951097 on 2016/04/21 by Thomas.Sarkanen Standalone games now benefit from parallel anim update if possible We now simply use the fact we want root motion to determine if we need to run immediately. #jira UE-29431 - Parallel anim update does not work in non-multiplayer games Change 2951036 on 2016/04/21 by Lee.Clark PS4 - Fix WinDualShock working with VS2015 #jira UE-29088 Change 2951034 on 2016/04/21 by Jack.Porter ProtoStar: Removed content not needed by remaining maps, resaved all content to fix version 0 issues #jira UE-29666 Change 2950995 on 2016/04/21 by Jack.Porter ProtoStar - delete unneeded maps #jira UE-29665 Change 2950787 on 2016/04/20 by Nick.Darnell SuperSearch - Moving the settings object into a seperate plugin to avoid there needing to be a circular dependency between SuperSearch and UnrealEd. #jira UE-29749 #codeview Ben.Marsh Change 2950786 on 2016/04/20 by Nick.Darnell Back out changelist 2950769 - Going to re-enable super search - about to move the settings into a plugin to prevent the circular reference. #jira UE-29749 Change 2950769 on 2016/04/20 by Ben.Marsh Comment out editor integration for super search to fix problems with the circular dependencies breaking hot reload and compiling QAGame in binary release. Change 2950724 on 2016/04/20 by Lina.Halper Support for negative scaling for mirroring - Merging CL 2950718 using //UE4/Dev-Framework_to_//UE4/Release-4.12 #jira: UE-27453 Change 2950293 on 2016/04/20 by andrew.porter Correcting sequencer test content #jira UE-29618 Change 2950283 on 2016/04/20 by Marc.Audy Don't route FlushPressedKeys on PIE shut down #jira UE-28734 Change 2950071 on 2016/04/20 by mason.seay Adjusted translation retargeting on head bone of UE4_Mannequin -Needed for anim bp test. Tested animations and did not see any fallout from change. If there is, it can be reverted. #jira UE-29618 Change 2950049 on 2016/04/20 by Mark.Satterthwaite Undo CL #2949690 and instead on Mac where we want to be able to capture videos of gameplay we just insert an intermediate texture as the back-buffer and use a manual blit to the drawable prior to present. This also changes the code to enforce that the back-buffer render-target should never be nil as the code & Metal API itself assumes that this situation cannot occur but it would appear from continued crashes inside PrepareToDraw that it actually can in the field. This will address another potential cause of UE-29006. #jira UE-29006 #jira UE-29140 Change 2949977 on 2016/04/20 by Max.Chen Sequencer: Add FieldOfView to default tracks for CameraActor. Add FieldOfView to exclusion list for CineCameraActor. #jira UE-29660 Change 2949836 on 2016/04/20 by Gareth.Martin Fix landscape components flickering when perfectly flat (bounds size is 0) - This often happens for newly created landscapes #jira UE-29262 Change 2949768 on 2016/04/20 by Thomas.Sarkanen Moving parent & grouped child actors now does not result in deltas being applied twice Grouping and attachment now interact correctly. Also fixed up according to coding standard. Discovered and proposed by David.Bliss2 (Rocksteady). #jira UE-29233 - Delta applied twice when moving parent and grouped child actors From UDN: https://udn.unrealengine.com/questions/286537/moving-parent-grouped-child-actors-results-in-delt.html Change 2949759 on 2016/04/20 by Thomas.Sarkanen Fix split pins not working as anim graph node inputs Limit surface area of this change by only modifying the anim BP compiler. A better version might be to move the call in the general blueprint compiler but it is riskier. #jira UE-12326 - Splitting a struct in an Anim Blueprint does not work Change 2949739 on 2016/04/20 by Thomas.Sarkanen Fix layered bone per blend accessed from a struct in the fast-path Made sure that the fallback event is always built (logic was still split so if PatchFunctionNamesAndCopyRecordsInto aborted because of some unhandled case if might not have an event to call). Covered struct source->array dest case. Indicator icon is now built from the copy record itself, ensuring it is accurate to actual runtime data. #jira UE-29389 - Fast-Path: Layered Blend per Bone node failing to grab updated values from struct. Change 2949715 on 2016/04/20 by Max.Chen Sequencer: Fix mouse wheel zoom so it defaults to zooming in on the current time/frame. This is a toggleable option in the Editor Preferences (Zoom Position = Current Time or Mouse Position) #jira UE-29661 Change 2949712 on 2016/04/20 by Taizyd.Korambayil #jira UE-28544 adjusted Player crosshair to be centered Change 2949710 on 2016/04/20 by Alexis.Matte #jira UE-29477 Pixel Inspector, UI get polish and adding "scene color" inspect property Change 2949706 on 2016/04/20 by Alexis.Matte #jira UE-29475 #jira UE-29476 Favorite allow all UProperty to be favorite (the FStruct is now supported) Favorite scrollig is auto adjust to avoid scrolling when adding/removing a favorite Change 2949691 on 2016/04/20 by Mark.Satterthwaite Fix typo from previous commit - retain not release... #jira UE-29140 Change 2949690 on 2016/04/20 by Mark.Satterthwaite Double-buffer the Metal viewport's back-buffer so that we can access the contents of the back-buffer after EndDrawingViewport is called until BeginDrawingViewport is called again on this viewport, this makes it possible to capture movies on Metal. #jira UE-29140 Change 2949616 on 2016/04/20 by Marc.Audy 'Merge' latest version of Vulkan from Dev-Rendering to Release-4.12 #jira UE-00000 Change 2949572 on 2016/04/20 by Jamie.Dale Fixed crash undoing a text property changed caused by a null entry in the array #jira UE-20223 Change 2949562 on 2016/04/20 by Alexis.Matte #jira UE-29447 Fix the batch fbx import "not show options" dialog where some option can be different. Change 2949560 on 2016/04/20 by Alexis.Matte #jira UE-28898 Avoid importing multiple static mesh in the same package Change 2949547 on 2016/04/20 by Mark.Satterthwaite You must use STENCIL_COMPONENT_SWIZZLE to access the stencil component of a texture - not all APIs can swizzle it into .g automatically. #jira UE-29672 Change 2949443 on 2016/04/20 by Allan.Bentham Disable sRGB textures when ES31 feature level is set. Only use vk's sRGB formats when feature level > ES3_1 #jira UE-29623 Change 2949428 on 2016/04/20 by Allan.Bentham Back out changelist 2949405 #jira UE-29623 Change 2949405 on 2016/04/20 by Allan.Bentham Disable sRGB textures when ES31 feature level is set. Only use vk's sRGB formats when feature level > ES3_1 #jira UE-29623 Merging using Dev-Mobile_->_Release-4.12 Change 2949391 on 2016/04/20 by Richard.TalbotWatkin PIE with multiple windows now starts focused on Client 1, or the server if not a dedicated server. Added a new virtual call UEditorEngine::OnLoginPIEAllComplete, called when all clients have been successfully logged in when starting PIE. The default behavior is to set focus to the first client. #jira UE-26037 - Cumbersome workflow when running PIE with 2 clients #jira UE-26905 - First client window does not gain focus or mouse control when launching two clients Change 2949389 on 2016/04/20 by Richard.TalbotWatkin Fixed regression which was saving the viewport config settings incorrectly. Viewports are keyed by their layout on the same key as the config key, hence we do not need to prepend the SpecificLayoutString when saving out the config data when iterating through a layout's viewports. #jira UE-29058 - Viewport settings are not saved after shutting down editor Change 2949388 on 2016/04/20 by Richard.TalbotWatkin Change auto-reimport settings so that "Detect Changes on Startup" defaults to true. Also removed the warning of potential unwanted behaviour when working in conjunction with source control; this is no longer necessary now that there is a prompt prior to auto-reimport. #jira UE-29257 - Auto import does not import assets Change 2949203 on 2016/04/19 by Max.Chen Sequencer: Fix spawnables not getting default tracks. #jira UE-29644 Change 2949202 on 2016/04/19 by Max.Chen Sequencer: Fix particles not firing on loop. #jira UE-27881 Change 2949201 on 2016/04/19 by Max.Chen Sequencer: Fix multiple labels support #jira UE-26812 Change 2949200 on 2016/04/19 by Max.Chen Sequencer: Expose settings sequencer settings in the Editor Preferences page. Note, UMG and Niagara have separate sequencer settings pages. #jira UE-29516 Change 2949197 on 2016/04/19 by Max.Chen Sequencer: Fix unwind rotation when keying rotation so that rotations are always set to the nearest. #jira UE-22228 Change 2949196 on 2016/04/19 by Max.Chen Sequencer: Disable selection range drawing if it's empty so that playback range dragging can take precedence when they overlap. This fixes a bug where you can't drag the starting playback range when sequencer starts up. #jira UE-29657 Change 2949195 on 2016/04/19 by Max.Chen MovieSceneCapture: Default image compression quality to 100 (rather than 75). #jira UE-29657 Change 2949194 on 2016/04/19 by Max.Chen Sequencer: Matinee to Level Sequence fix for mapping properties correctly. This fixes focus distance not getting set properly on the conversion. #jira UETOOL-467 Change 2949193 on 2016/04/19 by Max.Chen Sequencer - Fix issues with level visibility. + Don't mark sub-levels as dirty when the track evaluates. + Fix an issue where sequencer gets into a refresh loop because drawing thumbnails causes levels to be added which was rebuilding the tree, which was redrawing thumbnails. + Null check for when an objects world is null but the track is still evaluating. + Remove UnrealEd references. #jira UE-25668 Change 2948990 on 2016/04/19 by Aaron.McLeran #jira UE-29654 FadeIn invalidates Audio Components in 4.11 Change 2948890 on 2016/04/19 by Jamie.Dale Downgraded an assert in SPathView::LoadSettings to avoid a common crash when a saved path no longer exists #jira UE-28858 Change 2948860 on 2016/04/19 by Mike.Beach Mirroring CL 2940334 (from Dev-Blueprints): Bettering CreateEvent node errors, so users are able to recover from API changes (not clearing the function name field, calling out the function by name in the error, etc.) #jira UE-28911 Change 2948857 on 2016/04/19 by Jamie.Dale Added an Asset Localization context menu to the Content Browser This allows you to create, edit, and view localized assets from any source asset, as well as edit and view source assets from any localized asset. #jira UE-29493 Change 2948854 on 2016/04/19 by Jamie.Dale UAT now stages all project translation targets #jira UE-20248 Change 2948831 on 2016/04/19 by Mike.Beach Mirroring CL 2945994 (from Dev-Blueprints): Pasting EdGraphNodes will no longer query sub-nodes for compatibility if the root cannot be pasted (for things like collapsed graphs, and anim state-machine nodes). #jira UE-29035 Change 2948825 on 2016/04/19 by Jamie.Dale Fixed shadow warning #jira UE-29212 Change 2948812 on 2016/04/19 by Marc.Audy Gracefully handle failure to load configurable engine classes #jira UE-26527 Change 2948791 on 2016/04/19 by Jamie.Dale Fixed regression in SEditableText bIsCaretMovedWhenGainFocus when using auto-complete Fixed regression in FSlateEditableTextLayout::SetText that caused it to call OnTextChanged when nothing had changed #jira UE-29494 #jira UE-28886 Change 2948761 on 2016/04/19 by Jamie.Dale Sub-fonts are now only used when they contain the character to be rendered #jira UE-29212 Change 2948718 on 2016/04/19 by Jamie.Dale Fixed an issue where FEnginePackageLocalizationCache could be initialized before CoreUObject was ready This is now done lazily, either when the first CDO tries to load an asset (which is after CoreUObject is ready), or after the first call to ProcessNewlyLoadedUObjects (if no CDO loads an asset). #jira UE-29649 Change 2948717 on 2016/04/19 by Jamie.Dale Removed the AssetRegistry's dependency on MessageLog It was only there to add a category that was only ever used by the AssetTools module. #jira UE-29649 Change 2948683 on 2016/04/19 by Phillip.Kavan [UE-18419] Fix GetClassDefaults nodes to update properly in response to structural BP class changes. change summary: - modified UK2Node_GetClassDefaults::CreateOutputPins() to bind/unbind delegate handlers for the OnChanged() & OnCompile() events for BP class types. #jira UE-18419 Change 2948681 on 2016/04/19 by Phillip.Kavan [UE-17794] The "Delete Unused Variable" feature now considers the GetClassDefaults node as well. change summary: - added external linkage to UK2Node_GetClassDefaults::FindClassPin(). - added an include for the K2Node_GetClassDefaults header file to BlueprintGraphDefinitions.h. - added UK2Node_GetClassDefaults::GetInputClass() as a public API w/ external linkage; moved default 'nullptr' param logic into this impl. - modified FBlueprintEditorUtils::IsVariableUsed() to add an extra check for a GetClassDefaults node with a visible output pin for the variable that's also connected. - modified UK2Node_GetClassDefaults::GetInputClass() to return the generated skeleton class for Blueprint class types. #jira UE-17794 Change 2948638 on 2016/04/19 by Lee.Clark PS4 - Fix SDK compile warnings #jira UE-29647 Change 2948401 on 2016/04/19 by Taizyd.Korambayil #jira UE-29250 Revuilt Lighting for Landscapes Map Change 2948398 on 2016/04/19 by Mark.Satterthwaite Add a Mac Metal ES2 shader platform to allow the various ES2 emulation modes to work in the Editor. Fix various issues with the shader code to ensure that Metal can run with ES2 shader code at least in my limited test cases in QAGame. #jira UE-29170 Change 2948366 on 2016/04/19 by Taizyd.Korambayil #jira UE-29109 Replaced Box Mesh with BSP Floor Change 2948360 on 2016/04/19 by Maciej.Mroz merged from Dev-Blueprints 2947488 #jira UE-29115 Nativized BulletTrain - cannot shoot targets in intro tutorial #jira UE-28965 Packaging Project with Nativize Blueprint Assets Prevents Overlap Events from Firing #jira UE-29559 - fixed private enum access - fixed private bitfield access - removed forced PostLoad - add BodyInstance.FixupData call to fix ResponseChannels - ignored RelativeLocation and RelativeRotation in converted root component - fixed AttachToComponent (UE-29559) Change 2948358 on 2016/04/19 by Maciej.Mroz merged from Dev-Blueprints 2947953 #jira UE-29605 Wrong bullet trails in nativized ShowUp Fixed USimpleConstructionScript::GetSceneRootComponentTemplate. Change 2948357 on 2016/04/19 by Maciej.Mroz merged from Dev-Blueprints 2947984 #jira UE-29374 Crash when hovering over Create Widget node in blueprints Safe UK2Node_ConstructObjectFromClass::GetPinHoverText. Change 2948353 on 2016/04/19 by Maciej.Mroz merged from Dev-Blueprints 2948095 #jira UE-29246 ExpandEnumAsExecs + UMETA(Hidden) Crashes Blueprint Compile "Hidden" and "Spacer" elementa from an enum does not generated exec pins for "ExpandEnumAsExecs" Change 2948332 on 2016/04/19 by Benn.Gallagher Fixed old pins being left as non-transactional #jira UE-13801 Change 2948203 on 2016/04/19 by Lee.Clark PS4 - Use SDK 3.508.031 #jira UEPLAT-1225 Change 2948168 on 2016/04/19 by mason.seay Updating test content: -Added Husk AI to level to test placed AI -Updated Spawn Husk BP to destroy itself to prevent spawn spamming #jira UE-29618 Change 2948153 on 2016/04/19 by Benn.Gallagher Missed mesh update for Owen IK fix. #jira UE-22540 Change 2948130 on 2016/04/19 by Benn.Gallagher Fixed old Owen punch IK setup so it no longer jitters when placing the hands on the surface. #jira UE-22540 Change 2948117 on 2016/04/19 by Taizyd.Korambayil #jira UE-28477 Resaved Template Map's to fix Warning Toast on Templates Change 2948063 on 2016/04/19 by Lina.Halper - Anim composite notify change for better - Fixed all nested anim notify - Merging CL 2944396 using //UE4/Dev-Framework_to_//UE4/Release-4.12 #jira : UE-29101 Change 2948060 on 2016/04/19 by Lina.Halper Fix for composite section metadata saving for montage Merging CL 2944397 using //UE4/Dev-Framework_to_//UE4/Release-4.12 #jira : UE-29228 Change 2948029 on 2016/04/19 by Ben.Marsh EC: Prevent automatically pushing CIS builds to the launcher; the changelist might be run more than once. Change 2947986 on 2016/04/19 by Benn.Gallagher Fixed BP callable functions that affect skeletal mesh component transforms not working when simulating physics. #jira UE-27783 Change 2947976 on 2016/04/19 by Mark.Satterthwaite Duplicate CL #2943702 from 4.11.2: Change the way Metal validates the render-target state so that in FMetalContext::PrepareToDraw it can issue a last-ditch attempt to restore the render-targets. This won't fix the cause of the Mac Metal crashes but it might mitigate some of them and provide more information about why they are occurring. #jira UE-29006 Change 2947975 on 2016/04/19 by Mark.Satterthwaite Duplicate CL #2945061 from UE4-UT: Address UT issue UE-29150 directly in the UT branch: users without a sufficiently up-to-date Xcode won't have the 'metal' offline shader compiler so will have to use the slower online compiled text shader format. #jira UE-29150 Change 2947679 on 2016/04/19 by Jack.Porter Fixed 4.12 branch not compiling with the 1.0.8 Vulkan SDK #jira UE-29601 Change 2947657 on 2016/04/18 by Jack.Porter Update protostar reflection capture contents #jira UE-29600 Change 2947301 on 2016/04/18 by Ben.Marsh EC: Fix trigger ready emails failing to send due to recipient list being a space-separated list of addresses rather than an array reference. Change 2947263 on 2016/04/18 by Marc.Audy Merging CL# 2945921 //UE4/Release-4.11 to //UE4/Release-4.12 Ensure that all OwnedComponents in an Actor are duplicated for PIE even if not referenced by a property, unless that component is explicitly transient #jira UE-29209 Change 2946984 on 2016/04/18 by Ben.Marsh GUBP: Allow Ocean cooks in the release branch (fixes build startup failures) Change 2946870 on 2016/04/18 by Ben.Marsh Remaking CL 2946810 to fix compile error in ShooterGame editor. Change 2946859 on 2016/04/18 by Ben.Marsh GUBP: Don't exclude Ocean from builds in the release branch. Change 2946847 on 2016/04/18 by Ben.Marsh GUBP: Fix warning on every build step due to OrionGame_Win32_Mono no longer existing. Change 2946771 on 2016/04/18 by Ben.Marsh EC: Correct initial agent type for release branches. Causing full branch syncs on all agents. Change 2946641 on 2016/04/18 by Ben.Marsh EC: Remove rogue comma causing branch definition parsing to fail. Change 2946592 on 2016/04/18 by Ben.Marsh EC: Adding branch definition for 4.12 release #lockdown Nick.Penwarden [CL 2962354 by Ben Marsh in Main branch] --- .../epicgames/ue4/GooglePlayStoreHelper.java | 8 +- Engine/Build/BatchFiles/Build.bat | 12 +- Engine/Build/BatchFiles/Rebuild.bat | 29 +- Engine/Build/Commit.gitdeps.xml | 230 ++++++------ Engine/Config/BaseDeviceProfiles.ini | 1 - .../BaseEditorPerProjectUserSettings.ini | 4 +- Engine/Config/BaseEngine.ini | 2 +- .../Private/TileMapEditing/STileLayerList.cpp | 2 +- .../Private/SuperSearchEditorPrivatePCH.h | 5 + .../Private}/SuperSearchSettings.cpp | 18 +- .../Private}/SuperSearchSettings.h | 0 .../SuperSearchEditor.Build.cs | 20 + .../SuperSearchEditor.uplugin | 25 ++ .../Private/LevelSequenceEditorToolkit.cpp | 67 ++++ .../Misc/LevelSequenceEditorSettings.h | 8 + .../Private/MatineeToLevelSequenceModule.cpp | 38 +- .../BasePassForForwardShadingCommon.usf | 2 +- Engine/Shaders/BasePassPixelShader.usf | 104 ++++-- Engine/Shaders/Common.usf | 9 +- Engine/Shaders/Definitions.usf | 4 + Engine/Shaders/GpuSkinVertexFactory.usf | 2 +- Engine/Shaders/MaterialTemplate.usf | 2 +- Engine/Shaders/PostProcessAmbient.usf | 34 +- .../Shaders/PostProcessSelectionOutline.usf | 16 +- .../ReflectionEnvironmentComputeShaders.usf | 168 ++++----- .../Shaders/ReflectionEnvironmentShaders.usf | 121 +++--- .../Shaders/ReflectionEnvironmentShared.usf | 79 ++++ Engine/Shaders/ShadingModels.usf | 26 ++ .../Private/MetalBackend.cpp | 4 +- .../MetalShaderFormat/Private/MetalBackend.h | 2 +- .../Private/MetalShaderCompiler.cpp | 112 +++--- .../Private/MetalShaderFormat.cpp | 4 +- .../Developer/AssetTools/AssetTools.Build.cs | 2 + .../AssetTools/Private/AssetTools.cpp | 2 +- .../AssetTools/Private/AssetToolsModule.cpp | 14 + .../AssetTypeActions_ClassTypeBase.h | 2 + .../AssetTypeActions/AssetTypeActions_Enum.h | 1 + .../AssetTypeActions_Redirector.h | 1 + .../AssetTypeActions_Struct.h | 1 + .../AssetTypeActions/AssetTypeActions_World.h | 1 + .../AssetTools/Public/AssetTypeActions_Base.h | 5 + .../AssetTools/Public/IAssetTypeActions.h | 3 + .../BlueprintCompilerCppBackendUtils.cpp | 19 +- ...BlueprintCompilerCppBackendValueHelper.cpp | 92 +++-- .../Private/BlueprintNativeCodeGenModule.cpp | 5 + .../Private/GenericMacTargetPlatform.h | 2 + .../Private/SourceControlModule.cpp | 2 - .../AnimGraph/Classes/AnimStateNodeBase.h | 3 + .../AnimGraphNode_RotationMultiplier.cpp | 2 +- .../AnimGraphNode_TwistCorrectiveNode.cpp | 2 +- .../AnimGraph/Private/AnimPreviewInstance.cpp | 92 +++-- .../AnimGraph/Private/AnimStateNodeBase.cpp | 32 ++ .../Classes/K2Node_GetClassDefaults.h | 24 +- .../Private/DelegateNodeHandlers.cpp | 4 +- .../Private/K2Node_CallFunction.cpp | 8 +- .../K2Node_ConstructObjectFromClass.cpp | 19 +- .../Private/K2Node_CreateDelegate.cpp | 61 ++- .../Private/K2Node_GetClassDefaults.cpp | 46 ++- .../Private/K2Node_MakeStruct.cpp | 97 ++--- .../Private/K2Node_SpawnActorFromClass.cpp | 30 +- .../Public/BlueprintGraphDefinitions.h | 1 + .../AssetTypeActions_EditorUtilityBlueprint.h | 1 + .../ClassViewer/Private/SClassViewer.cpp | 137 +++---- .../Editor/ClassViewer/Private/SClassViewer.h | 5 +- .../Private/AssetContextMenu.cpp | 350 +++++++++++++++++- .../ContentBrowser/Private/AssetContextMenu.h | 35 ++ .../ContentBrowser/Private/SAssetView.cpp | 53 +-- .../Private/SContentBrowser.cpp | 12 +- .../ContentBrowser/Private/SPathView.cpp | 9 +- .../Private/CurveStructCustomization.cpp | 7 +- .../Private/TextCustomization.cpp | 45 +-- .../Private/CurveEditorViewportClient.cpp | 8 +- .../EditorStyle/Private/SlateEditorStyle.cpp | 4 +- .../SGraphNodeK2CreateDelegate.cpp | 13 +- .../Private/AnimBlueprintCompiler.cpp | 77 ++-- .../Private/LandscapeEdModeSplineTools.cpp | 5 + .../Private/LandscapeSplineImportExport.cpp | 2 +- .../Private/LandscapeSplineImportExport.h | 2 +- .../Private/LevelEditorActions.cpp | 47 ++- .../LevelEditor/Private/LevelEditorMenu.cpp | 2 +- .../Private/LevelEditorToolBar.cpp | 8 +- .../Private/LevelViewportLayout.cpp | 3 +- .../LevelEditor/Public/LevelViewportLayout.h | 2 +- .../CurveKeyAreas/FloatCurveKeyArea.cpp | 5 + .../Private/CurveKeyAreas/IntegralKeyArea.cpp | 4 + .../MovieSceneTools/Public/IntegralKeyArea.h | 11 + .../Persona/Private/SAnimNotifyPanel.cpp | 7 +- .../Editor/Persona/Private/SSkeletonTree.cpp | 2 +- .../PixelInspector/Private/PixelInspector.cpp | 298 +++++++++++++-- .../PixelInspector/Private/PixelInspector.h | 42 ++- .../PixelInspectorDetailsCustomization.cpp | 53 ++- .../PixelInspectorDetailsCustomization.h | 4 +- .../Private/PixelInspectorModule.cpp | 40 +- .../Private/PixelInspectorResult.cpp | 11 + .../Private/PixelInspectorResult.h | 5 + .../Private/PixelInspectorStyle.cpp | 2 + .../Private/PixelInspectorView.cpp | 6 +- .../Private/PixelInspectorView.h | 15 +- .../Public/PixelInspectorModule.h | 13 +- .../Private/DetailCategoryBuilderImpl.cpp | 6 + .../Private/DetailCategoryBuilderImpl.h | 3 + .../Private/DetailLayoutBuilderImpl.cpp | 5 + .../Private/DetailLayoutBuilderImpl.h | 5 + .../Private/IDetailsViewPrivate.h | 12 + .../Private/PropertyHandleImpl.cpp | 90 ++++- .../Private/PropertyHandleImpl.h | 5 +- .../PropertyEditor/Private/PropertyNode.h | 10 + .../Private/SDetailSingleItemRow.cpp | 80 ++++ .../PropertyEditor/Private/SDetailsView.cpp | 16 + .../PropertyEditor/Private/SDetailsView.h | 6 + .../Private/SDetailsViewBase.cpp | 29 +- .../Private/SStructureDetailsView.h | 1 + .../PropertyEditor/Public/PropertyHandle.h | 23 +- .../Private/ActorRecording.cpp | 2 +- .../Editor/Sequencer/Private/SSequencer.cpp | 4 +- .../Private/SSequencerLabelBrowser.cpp | 47 ++- .../Editor/Sequencer/Private/Sequencer.cpp | 57 ++- .../Editor/Sequencer/Private/Sequencer.h | 7 +- .../Sequencer/Private/SequencerNodeTree.cpp | 64 +++- .../Sequencer/Private/SequencerSettings.cpp | 30 +- .../Sequencer/Private/SequencerSettings.h | 88 +++-- .../Private/SequencerTimeSliderController.cpp | 38 +- .../Editor/Sequencer/Public/ISequencer.h | 5 +- .../AssetTypeActions_WidgetBlueprint.h | 1 + .../Private/WidgetBlueprintEditorUtils.cpp | 2 +- .../UnrealEd/Classes/Editor/EditorEngine.h | 11 + .../Classes/MaterialGraph/MaterialGraphNode.h | 2 + .../Settings/EditorLoadingSavingSettings.h | 8 +- .../Animation/EditorCompositeSection.cpp | 25 +- .../UnrealEd/Private/EdGraphUtilities.cpp | 6 +- .../Editor/UnrealEd/Private/EditorEngine.cpp | 2 +- .../UnrealEd/Private/EditorViewportClient.cpp | 29 +- .../Private/Factories/EditorFactories.cpp | 58 ++- .../UnrealEd/Private/Fbx/FbxFactory.cpp | 7 +- .../UnrealEd/Private/Fbx/FbxMainImport.cpp | 4 +- .../Private/Fbx/FbxSceneImportFactory.cpp | 8 +- .../Private/Fbx/FbxStaticMeshImport.cpp | 2 +- .../Editor/UnrealEd/Private/FileHelpers.cpp | 2 +- .../Editor/UnrealEd/Private/GroupActor.cpp | 29 +- .../Private/Kismet2/BlueprintEditorUtils.cpp | 18 +- .../Private/Kismet2/ComponentEditorUtils.cpp | 2 +- .../UnrealEd/Private/MRUFavoritesList.cpp | 46 +-- .../Editor/UnrealEd/Private/MRUList.cpp | 48 ++- .../Editor/UnrealEd/Private/PlayLevel.cpp | 42 ++- .../Private/Settings/SettingsClasses.cpp | 61 +-- .../Private/Toolkits/AssetEditorManager.cpp | 8 + .../UnrealEd/Private/UnrealEdEngine.cpp | 2 - .../Source/Editor/UnrealEd/Public/Factories.h | 2 +- .../Source/Editor/UnrealEd/Public/MRUList.h | 2 +- .../Public/Toolkits/AssetEditorManager.h | 1 + .../Source/Editor/UnrealEd/UnrealEd.Build.cs | 8 +- .../AutomationUtils/ProjectUtils.cs | 17 +- .../AutomationTool/GUBP/ElectricCommander.cs | 2 +- .../Private/ShaderCompileWorker.cpp | 4 +- .../Configuration/UEBuildTarget.cs | 4 + .../UnrealBuildTool/System/UProjectInfo.cs | 40 ++ .../System/VCProjectFileGenerator.cs | 7 - .../AnimNode_TwistCorrectiveNode.h | 5 +- .../Private/Widgets/Colors/SColorPicker.cpp | 8 +- .../Widgets/Colors/SEyeDropperButton.cpp | 6 +- .../Widgets/Colors/SEyeDropperButton.h | 4 +- .../Public/Widgets/Colors/SColorPicker.h | 2 +- .../MetalRHI/Private/MetalCommandEncoder.cpp | 7 + .../MetalRHI/Private/MetalCommandEncoder.h | 3 + .../Apple/MetalRHI/Private/MetalCommands.cpp | 4 +- .../Apple/MetalRHI/Private/MetalContext.cpp | 36 +- .../Apple/MetalRHI/Private/MetalRHI.cpp | 2 +- .../MetalRHI/Private/MetalStateCache.cpp | 23 +- .../Apple/MetalRHI/Private/MetalStateCache.h | 5 +- .../Apple/MetalRHI/Private/MetalTexture.cpp | 2 +- .../Apple/MetalRHI/Private/MetalViewport.cpp | 15 +- .../Apple/MetalRHI/Public/MetalViewport.h | 2 +- .../Private/AssetRegistryModule.cpp | 26 -- .../Core/Private/Android/AndroidMisc.cpp | 18 +- .../Core/Private/IOS/IOSPlatformFile.cpp | 6 +- .../Runtime/Core/Public/Math/Transform.h | 74 +++- .../Core/Public/Math/TransformVectorized.h | 90 ++++- .../Public/UObject/FrameworkObjectVersion.h | 4 + .../PackageLocalizationManager.cpp | 27 +- .../PackageLocalizationUtil.cpp | 71 ++++ .../Private/UObject/UObjectGlobals.cpp | 42 +-- .../PackageLocalizationManager.h | 21 +- .../PackageLocalizationUtil.h | 41 ++ .../Engine/Classes/Animation/AnimComposite.h | 2 + .../Classes/Animation/AnimCompositeBase.h | 7 + .../Engine/Classes/Animation/AnimInstance.h | 3 + .../Engine/Classes/Animation/AnimMontage.h | 1 - .../Classes/Animation/AnimSequenceBase.h | 4 +- .../Animation/AnimSingleNodeInstance.h | 4 +- .../Classes/Components/ChildActorComponent.h | 6 +- .../Classes/Components/SceneComponent.h | 2 + .../Components/SkeletalMeshComponent.h | 2 + .../Classes/Components/SplineComponent.h | 19 +- .../Classes/Engine/BlueprintGeneratedClass.h | 2 +- .../Engine/Classes/Engine/DemoNetDriver.h | 3 + .../Classes/Engine/DemoPendingNetGame.h | 7 + .../Classes/Engine/GameViewportClient.h | 6 - .../Engine/Classes/Engine/PendingNetGame.h | 6 + .../Engine/Classes/Engine/RendererSettings.h | 6 + .../Runtime/Engine/Classes/Engine/World.h | 2 +- .../Engine/Classes/GameFramework/Actor.h | 9 +- ...ialExpressionClearCoatNormalCustomOutput.h | 39 ++ .../Source/Runtime/Engine/Private/Actor.cpp | 20 + .../Engine/Private/ActorConstruction.cpp | 7 - .../Private/Animation/AnimComposite.cpp | 73 ++-- .../Private/Animation/AnimCompositeBase.cpp | 17 + .../Engine/Private/Animation/AnimInstance.cpp | 20 +- .../Private/Animation/AnimInstanceProxy.cpp | 38 +- .../Private/Animation/AnimSequenceBase.cpp | 13 +- .../Animation/AnimSingleNodeInstance.cpp | 99 ++++- .../Animation/AnimSingleNodeInstanceProxy.cpp | 90 +---- .../Private/BlueprintGeneratedClass.cpp | 30 +- .../Private/Components/AudioComponent.cpp | 2 +- .../Components/ChildActorComponent.cpp | 134 ++++--- .../Components/SkeletalMeshComponent.cpp | 16 + .../Private/Components/SplineComponent.cpp | 29 +- .../Runtime/Engine/Private/DemoNetDriver.cpp | 240 +++++++----- .../Engine/Private/GameViewportClient.cpp | 107 +----- .../Private/Materials/MaterialExpressions.cpp | 52 +++ .../Private/Particles/ParticleComponents.cpp | 13 +- .../Runtime/Engine/Private/PendingNetGame.cpp | 22 ++ .../Engine/Private/PlayerCameraManager.cpp | 9 +- .../Private/ShaderCompiler/ShaderCompiler.cpp | 5 + .../Private/SimpleConstructionScript.cpp | 5 +- .../Engine/Private/Slate/SceneViewport.cpp | 2 +- .../Engine/Private/TickTaskManager.cpp | 80 ++-- .../Runtime/Engine/Private/UnrealEngine.cpp | 92 ++--- .../Engine/Private/UserInterface/Console.cpp | 144 ++++--- .../Source/Runtime/Engine/Private/World.cpp | 40 +- .../Public/Animation/AnimInstanceProxy.h | 23 +- .../Animation/AnimSingleNodeInstanceProxy.h | 23 +- .../Runtime/Engine/Public/SceneInterface.h | 2 +- .../EngineSettings/Classes/ConsoleSettings.h | 4 + .../Abilities/GameplayAbilityTargetActor.cpp | 5 - .../Abilities/GameplayAbilityWorldReticle.cpp | 5 - .../Tasks/AbilityTask_VisualizeTargeting.cpp | 2 +- .../Tasks/AbilityTask_WaitTargetData.cpp | 2 +- .../Abilities/GameplayAbilityTargetActor.h | 3 +- .../Abilities/GameplayAbilityWorldReticle.h | 3 +- .../MaterialExpressionLandscapeLayerBlend.h | 1 - .../Landscape/Private/LandscapeEdit.cpp | 5 + .../Landscape/Private/LandscapeSplines.cpp | 11 +- .../MaterialExpressionLandscapeLayerBlend.cpp | 7 +- .../Launch/Private/LaunchEngineLoop.cpp | 46 ++- .../Private/LevelSequenceObjectReference.cpp | 2 +- .../Private/LevelSequenceSpawnRegister.cpp | 47 +-- .../LevelSequence/Public/LevelSequenceActor.h | 2 +- .../Public/IMovieSceneTrackInstance.h | 3 + .../Public/Protocols/ImageSequenceProtocol.h | 2 +- .../MovieSceneTracks.Build.cs | 5 - .../Sections/MovieScene3DTransformSection.cpp | 4 +- .../MovieSceneActorReferenceTrackInstance.cpp | 41 +- .../MovieSceneAudioTrackInstance.cpp | 5 +- ...MovieSceneLevelVisibilityTrackInstance.cpp | 29 +- .../MovieSceneParticleTrackInstance.cpp | 5 +- ...vieSceneSkeletalAnimationTrackInstance.cpp | 2 +- .../MovieSceneSubTrackInstance.cpp | 7 +- .../MovieSceneActorReferenceTrackInstance.h | 5 +- .../Private/Android/AndroidOpenGL.cpp | 34 +- .../OpenGLDrv/Private/Android/AndroidOpenGL.h | 5 + .../OpenGLDrv/Private/HTML5/HTML5OpenGL.cpp | 1 + .../OpenGLDrv/Private/OpenGLCommands.cpp | 4 +- .../OpenGLDrv/Private/OpenGLDevice.cpp | 13 +- .../Runtime/OpenGLDrv/Private/OpenGLES2.cpp | 4 + .../Runtime/OpenGLDrv/Private/OpenGLES31.cpp | 21 ++ .../OpenGLDrv/Private/OpenGLTexture.cpp | 14 +- .../Source/Runtime/OpenGLDrv/Public/OpenGL.h | 1 + .../Runtime/OpenGLDrv/Public/OpenGLES2.h | 4 + .../Runtime/OpenGLDrv/Public/OpenGLES31.h | 4 + Engine/Source/Runtime/RHI/Private/RHI.cpp | 8 +- .../Runtime/RHI/Public/RHIDefinitions.h | 156 ++++---- .../Renderer/Private/BasePassRendering.cpp | 23 +- .../Renderer/Private/BasePassRendering.h | 17 + .../Private/DeferredShadingRenderer.cpp | 8 + .../PostProcessBufferInspector.cpp | 21 ++ .../PostProcess/PostProcessBufferInspector.h | 2 +- .../Private/PostProcess/PostProcessing.cpp | 1 + .../PostProcess/SceneRenderTargets.cpp | 12 +- .../Renderer/Private/RendererScene.cpp | 14 +- .../Runtime/Renderer/Private/ScenePrivate.h | 5 +- .../Renderer/Private/VelocityRendering.cpp | 2 +- .../Runtime/ShaderCore/Private/Shader.cpp | 5 + .../ShaderCore/Private/ShaderCache.cpp | 1 + .../Framework/Application/MenuStack.cpp | 7 + .../Application/SlateApplication.cpp | 14 + .../Private/Widgets/Input/SEditableText.cpp | 16 +- .../Slate/Private/Widgets/Input/SSlider.cpp | 10 +- .../Widgets/Text/SMultiLineEditableText.cpp | 12 +- .../Widgets/Text/SlateEditableTextLayout.cpp | 30 +- .../Private/Widgets/Views/STableViewBase.cpp | 13 + .../Public/Framework/Application/MenuStack.h | 8 + .../Public/Widgets/Input/SEditableText.h | 1 + .../Widgets/Text/ISlateEditableTextWidget.h | 3 + .../Widgets/Text/SMultiLineEditableText.h | 1 + .../Public/Widgets/Views/STableViewBase.h | 3 + .../Private/Fonts/FontCacheCompositeFont.cpp | 42 ++- .../SlateCore/Private/Styling/CoreStyle.cpp | 3 +- .../SlateCore/Private/Styling/SlateTypes.cpp | 1 + .../SlateCore/Public/Styling/SlateTypes.h | 4 + .../VulkanRHI/Private/VulkanCommandBuffer.cpp | 131 ++----- .../VulkanRHI/Private/VulkanCommandBuffer.h | 51 +-- .../VulkanRHI/Private/VulkanCommands.cpp | 38 +- .../Runtime/VulkanRHI/Private/VulkanDebug.cpp | 50 +-- .../VulkanRHI/Private/VulkanDevice.cpp | 22 +- .../Runtime/VulkanRHI/Private/VulkanDevice.h | 13 +- .../VulkanRHI/Private/VulkanIndexBuffer.cpp | 23 +- .../VulkanRHI/Private/VulkanMemory.cpp | 172 +++++---- .../VulkanRHI/Private/VulkanPendingState.cpp | 119 ++---- .../VulkanRHI/Private/VulkanPendingState.h | 84 +---- .../Runtime/VulkanRHI/Private/VulkanQueue.cpp | 177 +-------- .../Runtime/VulkanRHI/Private/VulkanQueue.h | 19 - .../Runtime/VulkanRHI/Private/VulkanRHI.cpp | 100 ++--- .../VulkanRHI/Private/VulkanRHIPrivate.h | 18 +- .../VulkanRHI/Private/VulkanRenderTarget.cpp | 25 +- .../VulkanRHI/Private/VulkanShaders.cpp | 103 +++--- .../VulkanRHI/Private/VulkanSwapChain.cpp | 38 +- .../VulkanRHI/Private/VulkanSwapChain.h | 23 +- .../VulkanRHI/Private/VulkanTexture.cpp | 314 +++++----------- .../Runtime/VulkanRHI/Private/VulkanUAV.cpp | 4 +- .../Runtime/VulkanRHI/Private/VulkanUtil.cpp | 4 +- .../VulkanRHI/Private/VulkanViewport.cpp | 116 ++---- .../VulkanRHI/Public/VulkanConfiguration.h | 7 +- .../Runtime/VulkanRHI/Public/VulkanMemory.h | 77 +++- .../Runtime/VulkanRHI/Public/VulkanRHI.h | 2 + .../VulkanRHI/Public/VulkanResources.h | 79 +++- .../Runtime/VulkanRHI/Public/VulkanViewport.h | 14 +- .../Windows/D3D11RHI/Private/D3D11Texture.cpp | 4 +- .../Windows/D3D12RHI/Private/D3D12Texture.cpp | 6 +- README.md | 1 - 329 files changed, 5587 insertions(+), 3388 deletions(-) create mode 100644 Engine/Plugins/Editor/SuperSearchEditor/Source/SuperSearchEditor/Private/SuperSearchEditorPrivatePCH.h rename Engine/{Source/Editor/UnrealEd/Private/Settings => Plugins/Editor/SuperSearchEditor/Source/SuperSearchEditor/Private}/SuperSearchSettings.cpp (65%) rename Engine/{Source/Editor/UnrealEd/Private/Settings => Plugins/Editor/SuperSearchEditor/Source/SuperSearchEditor/Private}/SuperSearchSettings.h (100%) create mode 100644 Engine/Plugins/Editor/SuperSearchEditor/Source/SuperSearchEditor/SuperSearchEditor.Build.cs create mode 100644 Engine/Plugins/Editor/SuperSearchEditor/SuperSearchEditor.uplugin create mode 100644 Engine/Source/Runtime/CoreUObject/Private/Internationalization/PackageLocalizationUtil.cpp create mode 100644 Engine/Source/Runtime/CoreUObject/Public/Internationalization/PackageLocalizationUtil.h create mode 100644 Engine/Source/Runtime/Engine/Classes/Materials/MaterialExpressionClearCoatNormalCustomOutput.h diff --git a/Engine/Build/Android/Java/src/com/epicgames/ue4/GooglePlayStoreHelper.java b/Engine/Build/Android/Java/src/com/epicgames/ue4/GooglePlayStoreHelper.java index bfd75f204fe6..adbc59973751 100644 --- a/Engine/Build/Android/Java/src/com/epicgames/ue4/GooglePlayStoreHelper.java +++ b/Engine/Build/Android/Java/src/com/epicgames/ue4/GooglePlayStoreHelper.java @@ -86,12 +86,12 @@ public class GooglePlayStoreHelper implements StoreHelper /** * Query product details for the provided skus */ - public boolean QueryInAppPurchases(String[] ProductIDs, boolean[] bConsumable) + public boolean QueryInAppPurchases(String[] InProductIDs, boolean[] bConsumable) { Log.debug("[GooglePlayStoreHelper] - GooglePlayStoreHelper::QueryInAppPurchases"); ArrayList skuList = new ArrayList (); - for (String productId : ProductIDs) + for (String productId : InProductIDs) { Log.debug("[GooglePlayStoreHelper] - GooglePlayStoreHelper::QueryInAppPurchases - Querying " + productId); skuList.add(productId); @@ -107,6 +107,7 @@ public class GooglePlayStoreHelper implements StoreHelper int response = skuDetails.getInt("RESPONSE_CODE"); if (response == 0) { + ArrayList productIds = new ArrayList(); ArrayList titles = new ArrayList(); ArrayList descriptions = new ArrayList(); ArrayList prices = new ArrayList(); @@ -117,6 +118,7 @@ public class GooglePlayStoreHelper implements StoreHelper JSONObject object = new JSONObject(thisResponse); String productId = object.getString("productId"); + productIds.add(productId); Log.debug("[GooglePlayStoreHelper] - GooglePlayStoreHelper::QueryInAppPurchases - Parsing details for: " + productId); String title = object.getString("title"); @@ -133,7 +135,7 @@ public class GooglePlayStoreHelper implements StoreHelper } Log.debug("[GooglePlayStoreHelper] - GooglePlayStoreHelper::QueryInAppPurchases - Success!"); - nativeQueryComplete(true, ProductIDs, titles.toArray(new String[titles.size()]), descriptions.toArray(new String[descriptions.size()]), prices.toArray(new String[prices.size()])); + nativeQueryComplete(true, productIds.toArray(new String[productIds.size()]), titles.toArray(new String[titles.size()]), descriptions.toArray(new String[descriptions.size()]), prices.toArray(new String[prices.size()])); } else { diff --git a/Engine/Build/BatchFiles/Build.bat b/Engine/Build/BatchFiles/Build.bat index aed421f1eb55..eb30a119a0f1 100644 --- a/Engine/Build/BatchFiles/Build.bat +++ b/Engine/Build/BatchFiles/Build.bat @@ -11,9 +11,15 @@ REM %2 is the platform name REM %3 is the configuration name IF EXIST ..\..\Engine\Binaries\DotNET\UnrealBuildTool.exe ( - ..\..\Engine\Binaries\DotNET\UnrealBuildTool.exe %* -DEPLOY - popd - EXIT /B !ERRORLEVEL! + ..\..\Engine\Binaries\DotNET\UnrealBuildTool.exe %* -DEPLOY + popd + + REM Ignore exit codes of 2 ("ECompilationResult.UpToDate") from UBT; it's not a failure. + if "!ERRORLEVEL!"=="2" ( + EXIT /B 0 + ) + + EXIT /B !ERRORLEVEL! ) ELSE ( ECHO UnrealBuildTool.exe not found in ..\..\Engine\Binaries\DotNET\UnrealBuildTool.exe popd diff --git a/Engine/Build/BatchFiles/Rebuild.bat b/Engine/Build/BatchFiles/Rebuild.bat index 97647b7635a7..13e1e9bb0c99 100644 --- a/Engine/Build/BatchFiles/Rebuild.bat +++ b/Engine/Build/BatchFiles/Rebuild.bat @@ -4,16 +4,21 @@ REM %1 is the game name REM %2 is the platform name REM %3 is the configuration name -IF EXIST "%~dp0\Clean.bat" ( - call "%~dp0\Clean.bat" %* -) ELSE ( - ECHO Clean.bat not found in "%~dp0" - EXIT /B 999 -) +IF NOT EXIST "%~dp0\Clean.bat" GOTO Error_MissingCleanBatchFile -IF EXIST "%~dp0\Build.bat" ( - call "%~dp0\Build.bat" %* -) ELSE ( - ECHO Build.bat not found in "%~dp0" - EXIT /B 999 -) +call "%~dp0\Clean.bat" %* + +IF NOT EXIST "%~dp0\Build.bat" GOTO Error_MissingBuildBatchFile + +call "%~dp0\Build.bat" %* +GOTO Exit + +:Error_MissingCleanBatchFile +ECHO Clean.bat not found in "%~dp0" +EXIT /B 999 + +:Error_MissingBuildBatchFile +ECHO Build.bat not found in "%~dp0" +EXIT /B 999 + +:Exit diff --git a/Engine/Build/Commit.gitdeps.xml b/Engine/Build/Commit.gitdeps.xml index 3eeeddae1205..b432d24f9511 100644 --- a/Engine/Build/Commit.gitdeps.xml +++ b/Engine/Build/Commit.gitdeps.xml @@ -2066,7 +2066,7 @@ - + @@ -3779,6 +3779,7 @@ + @@ -4292,6 +4293,8 @@ + + @@ -13876,37 +13879,37 @@ - + - + - + - + - + - + - + - + @@ -14034,7 +14037,7 @@ - + @@ -14063,7 +14066,7 @@ - + @@ -26851,18 +26854,18 @@ - - - - - - - - - - - - + + + + + + + + + + + + @@ -28119,7 +28122,7 @@ - + @@ -28249,6 +28252,7 @@ + @@ -28393,7 +28397,6 @@ - @@ -28748,7 +28751,7 @@ - + @@ -28847,6 +28850,7 @@ + @@ -28877,7 +28881,7 @@ - + @@ -29816,7 +29820,7 @@ - + @@ -30116,7 +30120,7 @@ - + @@ -30235,7 +30239,6 @@ - @@ -30289,7 +30292,6 @@ - @@ -30354,7 +30356,7 @@ - + @@ -30746,7 +30748,7 @@ - + @@ -30940,7 +30942,7 @@ - + @@ -31013,6 +31015,7 @@ + @@ -31170,7 +31173,6 @@ - @@ -31233,7 +31235,7 @@ - + @@ -31812,7 +31814,6 @@ - @@ -31859,7 +31860,6 @@ - @@ -32111,7 +32111,7 @@ - + @@ -32631,6 +32631,7 @@ + @@ -32724,7 +32725,7 @@ - + @@ -33349,7 +33350,7 @@ - + @@ -33394,7 +33395,6 @@ - @@ -33658,6 +33658,7 @@ + @@ -33719,7 +33720,7 @@ - + @@ -33746,6 +33747,7 @@ + @@ -33789,8 +33791,8 @@ - - + + @@ -33834,7 +33836,6 @@ - @@ -33919,7 +33920,6 @@ - @@ -34089,7 +34089,6 @@ - @@ -34116,7 +34115,7 @@ - + @@ -34430,7 +34429,7 @@ - + @@ -34591,6 +34590,7 @@ + @@ -34964,7 +34964,7 @@ - + @@ -35299,6 +35299,7 @@ + @@ -35445,7 +35446,7 @@ - + @@ -35454,7 +35455,7 @@ - + @@ -35719,6 +35720,7 @@ + @@ -35729,7 +35731,7 @@ - + @@ -35850,7 +35852,7 @@ - + @@ -35946,7 +35948,7 @@ - + @@ -36132,6 +36134,7 @@ + @@ -36265,7 +36268,7 @@ - + @@ -36664,7 +36667,7 @@ - + @@ -37024,7 +37027,7 @@ - + @@ -37149,6 +37152,7 @@ + @@ -37205,6 +37209,7 @@ + @@ -37696,7 +37701,7 @@ - + @@ -38499,7 +38504,7 @@ - + @@ -38933,7 +38938,7 @@ - + @@ -39006,6 +39011,7 @@ + @@ -39189,6 +39195,7 @@ + @@ -39641,7 +39648,7 @@ - + @@ -39714,7 +39721,7 @@ - + @@ -40074,7 +40081,7 @@ - + @@ -40313,7 +40320,7 @@ - + @@ -40399,7 +40406,6 @@ - @@ -40534,7 +40540,7 @@ - + @@ -40621,7 +40627,6 @@ - @@ -40667,8 +40672,9 @@ - + + @@ -40746,6 +40752,7 @@ + @@ -40870,7 +40877,6 @@ - @@ -40938,7 +40944,6 @@ - @@ -41099,7 +41104,6 @@ - @@ -41399,7 +41403,7 @@ - + @@ -41431,7 +41435,7 @@ - + @@ -41803,7 +41807,6 @@ - @@ -42186,7 +42189,7 @@ - + @@ -42223,6 +42226,7 @@ + @@ -42928,7 +42932,7 @@ - + @@ -42954,6 +42958,7 @@ + @@ -43038,7 +43043,7 @@ - + @@ -43301,6 +43306,7 @@ + @@ -43545,7 +43551,7 @@ - + @@ -43647,7 +43653,7 @@ - + @@ -43787,7 +43793,7 @@ - + @@ -43801,6 +43807,7 @@ + @@ -43930,7 +43937,7 @@ - + @@ -44098,6 +44105,7 @@ + @@ -44118,7 +44126,7 @@ - + @@ -44216,7 +44224,7 @@ - + @@ -44708,7 +44716,7 @@ - + @@ -45107,6 +45115,7 @@ + @@ -45286,6 +45295,7 @@ + @@ -45441,7 +45451,7 @@ - + @@ -45487,7 +45497,7 @@ - + @@ -46092,7 +46102,7 @@ - + @@ -46211,7 +46221,6 @@ - @@ -46220,7 +46229,7 @@ - + @@ -46264,7 +46273,7 @@ - + @@ -46292,7 +46301,6 @@ - @@ -46360,17 +46368,17 @@ - + - + - + @@ -46378,7 +46386,7 @@ - + @@ -46490,8 +46498,8 @@ - - + + @@ -46763,7 +46771,6 @@ - @@ -46772,7 +46779,6 @@ - @@ -46784,7 +46790,6 @@ - @@ -46846,6 +46851,7 @@ + @@ -46856,7 +46862,6 @@ - @@ -46907,7 +46912,6 @@ - @@ -46998,7 +47002,6 @@ - @@ -47025,7 +47028,6 @@ - @@ -47087,6 +47089,7 @@ + @@ -47241,7 +47244,6 @@ - @@ -47397,6 +47399,7 @@ + @@ -47505,6 +47508,7 @@ + @@ -47636,7 +47640,6 @@ - @@ -47875,6 +47878,7 @@ + @@ -48057,6 +48061,7 @@ + @@ -48106,7 +48111,6 @@ - @@ -48171,7 +48175,6 @@ - @@ -48181,7 +48184,6 @@ - @@ -48280,6 +48282,7 @@ + @@ -48304,6 +48307,7 @@ + @@ -48334,6 +48338,7 @@ + @@ -48401,6 +48406,7 @@ + @@ -48444,7 +48450,6 @@ - @@ -48553,6 +48558,7 @@ + diff --git a/Engine/Config/BaseDeviceProfiles.ini b/Engine/Config/BaseDeviceProfiles.ini index 4fd631e55569..f9c061a33e3b 100644 --- a/Engine/Config/BaseDeviceProfiles.ini +++ b/Engine/Config/BaseDeviceProfiles.ini @@ -329,7 +329,6 @@ BaseProfileName=Android_High [Android_Adreno4xx_Nexus6 DeviceProfile] DeviceType=Android BaseProfileName=Android_Adreno4xx -+CVars=android.DisableTextureFormatBGRA8888=1 [Android_PowerVR54x DeviceProfile] DeviceType=Android diff --git a/Engine/Config/BaseEditorPerProjectUserSettings.ini b/Engine/Config/BaseEditorPerProjectUserSettings.ini index e781a04bf578..2bf69a6524a4 100644 --- a/Engine/Config/BaseEditorPerProjectUserSettings.ini +++ b/Engine/Config/BaseEditorPerProjectUserSettings.ini @@ -736,6 +736,6 @@ bInfiniteKeyAreas=true [/Script/LevelSequenceEditor.LevelSequenceEditorSettings] +TrackSettings=(MatchingActorClass=/Script/Engine.StaticMeshActor,DefaultTracks=(/Script/MovieSceneTracks.MovieScene3DTransformTrack)) +TrackSettings=(MatchingActorClass=/Script/Engine.SkeletalMeshActor,DefaultTracks=(/Script/MovieSceneTracks.MovieScene3DTransformTrack,/Script/MovieSceneTracks.MovieSceneSkeletalAnimationTrack)) -+TrackSettings=(MatchingActorClass=/Script/Engine.CameraActor,DefaultTracks=(/Script/MovieSceneTracks.MovieScene3DTransformTrack)) -+TrackSettings=(MatchingActorClass=/Script/CinematicCamera.CineCameraActor,DefaultPropertyTracks=((ComponentPath="CameraComponent",PropertyPath="CurrentFocalLength"),(ComponentPath="CameraComponent",PropertyPath="FocusSettings.ManualFocusDistance"),(ComponentPath="CameraComponent",PropertyPath="CurrentAperture"))) ++TrackSettings=(MatchingActorClass=/Script/Engine.CameraActor,DefaultTracks=(/Script/MovieSceneTracks.MovieScene3DTransformTrack),DefaultPropertyTracks=((ComponentPath="CameraComponent",PropertyPath="FieldOfView"))) ++TrackSettings=(MatchingActorClass=/Script/CinematicCamera.CineCameraActor,DefaultPropertyTracks=((ComponentPath="CameraComponent",PropertyPath="CurrentFocalLength"),(ComponentPath="CameraComponent",PropertyPath="FocusSettings.ManualFocusDistance"),(ComponentPath="CameraComponent",PropertyPath="CurrentAperture")),ExcludeDefaultPropertyTracks=((ComponentPath="CameraComponent",PropertyPath="FieldOfView"))) +TrackSettings=(MatchingActorClass=/Script/Engine.Light,DefaultTracks=(None),DefaultPropertyTracks=((ComponentPath="LightComponent0",PropertyPath="Intensity"),(ComponentPath="LightComponent0",PropertyPath="LightColor"))) diff --git a/Engine/Config/BaseEngine.ini b/Engine/Config/BaseEngine.ini index 0a4cbf69cbbf..2879dc5b760c 100644 --- a/Engine/Config/BaseEngine.ini +++ b/Engine/Config/BaseEngine.ini @@ -1372,7 +1372,7 @@ bUseStreamingPause=false ; SplineComponent API overhaul +K2FieldRedirects=(OldFieldName="SplineComponent.GetNumSplinePoints",NewFieldName="SplineComponent.GetNumberOfSplinePoints") - ++TaggedPropertyRedirects=(ClassName="SplineComponent",OldPropertyName="bAlwaysRenderInEditor",NewPropertyName="bDrawDebug") ; VER_UE4_INVERSE_SQUARED_LIGHTS_DEFAULT +K2FieldRedirects=(OldFieldName="LightComponentBase.Brightness",NewFieldName="LightComponentBase.Intensity") diff --git a/Engine/Plugins/2D/Paper2D/Source/Paper2DEditor/Private/TileMapEditing/STileLayerList.cpp b/Engine/Plugins/2D/Paper2D/Source/Paper2DEditor/Private/TileMapEditing/STileLayerList.cpp index 89b3f4e4f440..afca12baf915 100644 --- a/Engine/Plugins/2D/Paper2D/Source/Paper2DEditor/Private/TileMapEditing/STileLayerList.cpp +++ b/Engine/Plugins/2D/Paper2D/Source/Paper2DEditor/Private/TileMapEditing/STileLayerList.cpp @@ -31,7 +31,7 @@ public: } // FCustomizableTextObjectFactory interface - virtual bool CanCreateClass(UClass* ObjectClass) const override + virtual bool CanCreateClass(UClass* ObjectClass, bool& bOmitSubObjs) const override { // Only allow layers to be created return ObjectClass->IsChildOf(UPaperTileLayer::StaticClass()); diff --git a/Engine/Plugins/Editor/SuperSearchEditor/Source/SuperSearchEditor/Private/SuperSearchEditorPrivatePCH.h b/Engine/Plugins/Editor/SuperSearchEditor/Source/SuperSearchEditor/Private/SuperSearchEditorPrivatePCH.h new file mode 100644 index 000000000000..42173d07d96c --- /dev/null +++ b/Engine/Plugins/Editor/SuperSearchEditor/Source/SuperSearchEditor/Private/SuperSearchEditorPrivatePCH.h @@ -0,0 +1,5 @@ +// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. + +#include "Engine.h" +#include "UnrealEd.h" +#include "SuperSearchModule.h" diff --git a/Engine/Source/Editor/UnrealEd/Private/Settings/SuperSearchSettings.cpp b/Engine/Plugins/Editor/SuperSearchEditor/Source/SuperSearchEditor/Private/SuperSearchSettings.cpp similarity index 65% rename from Engine/Source/Editor/UnrealEd/Private/Settings/SuperSearchSettings.cpp rename to Engine/Plugins/Editor/SuperSearchEditor/Source/SuperSearchEditor/Private/SuperSearchSettings.cpp index bb6fb72c8321..f8ebe0cb4c5d 100644 --- a/Engine/Source/Editor/UnrealEd/Private/Settings/SuperSearchSettings.cpp +++ b/Engine/Plugins/Editor/SuperSearchEditor/Source/SuperSearchEditor/Private/SuperSearchSettings.cpp @@ -1,9 +1,25 @@ // Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. -#include "UnrealEd.h" +#include "SuperSearchEditorPrivatePCH.h" #include "SuperSearchSettings.h" +class FSuperSearchEditorModule : public FDefaultModuleImpl +{ +public: + virtual void StartupModule() override + { + } + + virtual void ShutdownModule() override + { + } +}; + +////////////////////////////////////////////////////////////////////////// + +IMPLEMENT_MODULE(FSuperSearchEditorModule, SuperSearchEditor); + void USuperSearchSettings::PostInitProperties() { Super::PostInitProperties(); diff --git a/Engine/Source/Editor/UnrealEd/Private/Settings/SuperSearchSettings.h b/Engine/Plugins/Editor/SuperSearchEditor/Source/SuperSearchEditor/Private/SuperSearchSettings.h similarity index 100% rename from Engine/Source/Editor/UnrealEd/Private/Settings/SuperSearchSettings.h rename to Engine/Plugins/Editor/SuperSearchEditor/Source/SuperSearchEditor/Private/SuperSearchSettings.h diff --git a/Engine/Plugins/Editor/SuperSearchEditor/Source/SuperSearchEditor/SuperSearchEditor.Build.cs b/Engine/Plugins/Editor/SuperSearchEditor/Source/SuperSearchEditor/SuperSearchEditor.Build.cs new file mode 100644 index 000000000000..1e82018e6345 --- /dev/null +++ b/Engine/Plugins/Editor/SuperSearchEditor/Source/SuperSearchEditor/SuperSearchEditor.Build.cs @@ -0,0 +1,20 @@ +// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. + +namespace UnrealBuildTool.Rules +{ + public class SuperSearchEditor : ModuleRules + { + public SuperSearchEditor(TargetInfo Target) + { + PublicDependencyModuleNames.AddRange( + new string[] + { + "Core", + "CoreUObject", + "Engine", + "SuperSearch" + } + ); + } + } +} \ No newline at end of file diff --git a/Engine/Plugins/Editor/SuperSearchEditor/SuperSearchEditor.uplugin b/Engine/Plugins/Editor/SuperSearchEditor/SuperSearchEditor.uplugin new file mode 100644 index 000000000000..6a64c8e6eedd --- /dev/null +++ b/Engine/Plugins/Editor/SuperSearchEditor/SuperSearchEditor.uplugin @@ -0,0 +1,25 @@ +{ + "FileVersion" : 3, + "Version" : 1, + "VersionName" : "1.0", + "FriendlyName" : "Super Search Editor", + "Description" : "Allows you to tweak the settings on super search.", + "Category" : "Editor", + "CreatedBy" : "Epic Games, Inc.", + "CreatedByURL" : "http://epicgames.com", + "DocsURL" : "", + "MarketplaceURL" : "", + "SupportURL" : "", + "EnabledByDefault" : true, + "CanContainContent" : false, + "IsBetaVersion" : false, + "Installed" : false, + "Modules" : + [ + { + "Name" : "SuperSearchEditor", + "Type" : "Editor", + "LoadingPhase" : "Default" + } + ] +} \ No newline at end of file diff --git a/Engine/Plugins/MovieScene/LevelSequenceEditor/Source/LevelSequenceEditor/Private/LevelSequenceEditorToolkit.cpp b/Engine/Plugins/MovieScene/LevelSequenceEditor/Source/LevelSequenceEditor/Private/LevelSequenceEditorToolkit.cpp index 0c13c0086cb9..0369fb4f4bc1 100644 --- a/Engine/Plugins/MovieScene/LevelSequenceEditor/Source/LevelSequenceEditor/Private/LevelSequenceEditorToolkit.cpp +++ b/Engine/Plugins/MovieScene/LevelSequenceEditor/Source/LevelSequenceEditor/Private/LevelSequenceEditorToolkit.cpp @@ -276,6 +276,26 @@ void FLevelSequenceEditorToolkit::AddDefaultTracksForActor(AActor& Actor, const { UClass* TrackClass = DefaultTrack.ResolveClass(); + // exclude any tracks explicitly marked for exclusion + for (const FLevelSequenceTrackSettings& ExcludeTrackSettings : GetDefault()->TrackSettings) + { + UClass* ExcludeMatchingActorClass = ExcludeTrackSettings.MatchingActorClass.ResolveClass(); + + if ((ExcludeMatchingActorClass == nullptr) || !Actor.IsA(ExcludeMatchingActorClass)) + { + continue; + } + + for (const FStringClassReference& ExcludeDefaultTrack : ExcludeTrackSettings.ExcludeDefaultTracks) + { + if (ExcludeDefaultTrack == DefaultTrack) + { + TrackClass = nullptr; + break; + } + } + } + if (TrackClass != nullptr) { UMovieSceneTrack* NewTrack = MovieScene->AddTrack(TrackClass, Binding); @@ -324,6 +344,46 @@ void FLevelSequenceEditorToolkit::AddDefaultTracksForActor(AActor& Actor, const } } + // construct a map of the properties that should be excluded per component + TMap > ExcludePropertyTracksMap; + for (const FLevelSequenceTrackSettings& ExcludeTrackSettings : GetDefault()->TrackSettings) + { + UClass* ExcludeMatchingActorClass = ExcludeTrackSettings.MatchingActorClass.ResolveClass(); + + if ((ExcludeMatchingActorClass == nullptr) || !Actor.IsA(ExcludeMatchingActorClass)) + { + continue; + } + + for (const FLevelSequencePropertyTrackSettings& PropertyTrackSettings : ExcludeTrackSettings.ExcludeDefaultPropertyTracks) + { + TArray PropertyPath; + UObject* PropertyOwner = &Actor; + + // determine object hierarchy + TArray ComponentNames; + PropertyTrackSettings.ComponentPath.ParseIntoArray(ComponentNames, TEXT(".")); + + for (const FString& ComponentName : ComponentNames) + { + PropertyOwner = FindObjectFast(PropertyOwner, *ComponentName); + + if (PropertyOwner == nullptr) + { + continue; + } + } + + if (PropertyOwner) + { + TArray PropertyNames; + PropertyTrackSettings.PropertyPath.ParseIntoArray(PropertyNames, TEXT(".")); + + ExcludePropertyTracksMap.Add(PropertyOwner, PropertyNames); + } + } + } + // add tracks by property for (const FLevelSequencePropertyTrackSettings& PropertyTrackSettings : TrackSettings.DefaultPropertyTracks) { @@ -352,6 +412,13 @@ void FLevelSequenceEditorToolkit::AddDefaultTracksForActor(AActor& Actor, const for (const FString& PropertyName : PropertyNames) { + // skip past excluded properties + if (ExcludePropertyTracksMap.Contains(PropertyOwner) && ExcludePropertyTracksMap[PropertyOwner].Contains(PropertyName)) + { + PropertyPath.Empty(); + break; + } + UProperty* Property = PropertyOwnerClass->FindPropertyByName(*PropertyName); if (Property != nullptr) diff --git a/Engine/Plugins/MovieScene/LevelSequenceEditor/Source/LevelSequenceEditor/Private/Misc/LevelSequenceEditorSettings.h b/Engine/Plugins/MovieScene/LevelSequenceEditor/Source/LevelSequenceEditor/Private/Misc/LevelSequenceEditorSettings.h index 100fcebe050a..916c79486715 100644 --- a/Engine/Plugins/MovieScene/LevelSequenceEditor/Source/LevelSequenceEditor/Private/Misc/LevelSequenceEditorSettings.h +++ b/Engine/Plugins/MovieScene/LevelSequenceEditor/Source/LevelSequenceEditor/Private/Misc/LevelSequenceEditorSettings.h @@ -36,9 +36,17 @@ struct FLevelSequenceTrackSettings UPROPERTY(config, noclear, EditAnywhere, Category=TrackSettings, meta=(MetaClass="MovieSceneTrack")) TArray DefaultTracks; + /** List of movie scene track classes not to be added automatically. */ + UPROPERTY(config, noclear, EditAnywhere, Category=TrackSettings, meta=(MetaClass="MovieSceneTrack")) + TArray ExcludeDefaultTracks; + /** List of property names for which movie scene tracks will be created automatically. */ UPROPERTY(config, EditAnywhere, Category=TrackSettings) TArray DefaultPropertyTracks; + + /** List of property names for which movie scene tracks will not be created automatically. */ + UPROPERTY(config, EditAnywhere, Category=TrackSettings) + TArray ExcludeDefaultPropertyTracks; }; diff --git a/Engine/Plugins/MovieScene/MatineeToLevelSequence/Source/MatineeToLevelSequence/Private/MatineeToLevelSequenceModule.cpp b/Engine/Plugins/MovieScene/MatineeToLevelSequence/Source/MatineeToLevelSequence/Private/MatineeToLevelSequenceModule.cpp index 069f22b209ab..3e06718f6b2d 100644 --- a/Engine/Plugins/MovieScene/MatineeToLevelSequence/Source/MatineeToLevelSequence/Private/MatineeToLevelSequenceModule.cpp +++ b/Engine/Plugins/MovieScene/MatineeToLevelSequence/Source/MatineeToLevelSequence/Private/MatineeToLevelSequenceModule.cpp @@ -231,8 +231,8 @@ protected: NewSequence->BindPossessableObject(ObjectGuid, *PropObject, GWorld); } + // cbb: String manipulations to get the property path in the rigth form for sequencer FString PropertyName = Property->GetFName().ToString(); - FString PropertyPath = Property->GetPathName(); // Special case for Light components which have some deprecated names if (PropObject->GetClass()->IsChildOf(ULightComponentBase::StaticClass())) @@ -245,17 +245,39 @@ protected: if (RemappedName != nullptr) { PropertyName = RemappedName->ToString(); - int32 LastDot = INDEX_NONE; - PropertyPath.FindLastChar(TCHAR(':'), LastDot); - if (LastDot != INDEX_NONE) - { - PropertyPath = PropertyPath.Left(LastDot) + TEXT(":") + PropertyName; - } } } + // Strip the object part of the property path + FString PropertyPath = Property->GetPathName(); + int32 DotPos = INDEX_NONE; + if (PropertyPath.FindLastChar(TEXT('.'), DotPos)) + { + PropertyPath = PropertyPath.RightChop(DotPos+1); + } + + // Split it into the components + TArray PropertyPaths; + PropertyPath.ParseIntoArray(PropertyPaths, TEXT(":")); + + // Reassemble path with "." separators + FString NewPropertyPath; + for (int32 PropertyIndex=0; PropertyIndexAddTrack(ObjectGuid); - PropertyTrack->SetPropertyNameAndPath(*PropertyName, PropertyPath); + PropertyTrack->SetPropertyNameAndPath(*PropertyName, NewPropertyPath); } else { diff --git a/Engine/Shaders/BasePassForForwardShadingCommon.usf b/Engine/Shaders/BasePassForForwardShadingCommon.usf index 28bf9b996c5b..d54a7b7eecb8 100644 --- a/Engine/Shaders/BasePassForForwardShadingCommon.usf +++ b/Engine/Shaders/BasePassForForwardShadingCommon.usf @@ -14,7 +14,7 @@ #define PACK_INTERPOLANTS (USE_VERTEX_FOG && NUM_VF_PACKED_INTERPOLANTS > 0 && (ES2_PROFILE || ES3_1_PROFILE)) #define LANDSCAPE_BUG_WORKAROUND (IOS && IS_FORWARD_BASEPASS_VERTEX_SHADER && PACK_INTERPOLANTS) -#if METAL_PROFILE +#if COMPILER_METAL // @todo-rco: @todo metal: FIXME! #define INTERP_TYPE float4 #else diff --git a/Engine/Shaders/BasePassPixelShader.usf b/Engine/Shaders/BasePassPixelShader.usf index 82a45fc5aa6b..282a28faa84c 100644 --- a/Engine/Shaders/BasePassPixelShader.usf +++ b/Engine/Shaders/BasePassPixelShader.usf @@ -54,6 +54,11 @@ SamplerState PrevSceneColorSampler; TextureCubeArray ReflectionCubemap; SamplerState ReflectionCubemapSampler; int CubemapArrayIndex; + float4 ReflectionPositionAndRadius; + float ReflectionShape; + float4x4 BoxTransform; + float4 BoxScales; + float3 CaptureOffset; #else TextureCube ReflectionCubemap; SamplerState ReflectionCubemapSampler; @@ -70,13 +75,53 @@ uint MortonCode( uint x ) half3 GetImageBasedReflectionLighting(FMaterialPixelParameters MaterialParameters, half Roughness, half3 SpecularColor, half IndirectIrradiance) { - half AbsoluteSpecularMip = ComputeReflectionCaptureMipFromRoughness(Roughness, Frame.ReflectionCubemapMaxMip); + float3 N = MaterialParameters.WorldNormal; + float3 V = MaterialParameters.CameraVector; + + float3 RayDirection = 2 * dot( V, N ) * N - V; + float3 RV = RayDirection; + half NoV = saturate(dot(N, V)); + + float RoughnessSq = Roughness * Roughness; + float AO = 1.0f; + float SpecularOcclusion = GetSpecularOcclusion(NoV, RoughnessSq, AO); + + float4 SpecularIBL = float4(0,0,0,SpecularOcclusion); + float3 CaptureVector = MaterialParameters.AbsoluteWorldPosition - ReflectionPositionAndRadius.xyz; + float CaptureVectorLength = length(CaptureVector); + + BRANCH + if (CaptureVectorLength < ReflectionPositionAndRadius.w) + { + float NormalizedDistanceToCapture = saturate(CaptureVectorLength / ReflectionPositionAndRadius.w); + + RV = GetOffSpecularPeakReflectionDir(N, RV, Roughness); + + float DistanceAlpha; + float3 ProjectedCaptureVector; + if (ReflectionShape > 0.0f) + { + ProjectedCaptureVector = GetLookupVectorForBoxCapture(RV, MaterialParameters.AbsoluteWorldPosition, ReflectionPositionAndRadius, BoxTransform, BoxScales, CaptureOffset, DistanceAlpha); + } + else + { + ProjectedCaptureVector = GetLookupVectorForSphereCapture(RV, MaterialParameters.AbsoluteWorldPosition, ReflectionPositionAndRadius, NormalizedDistanceToCapture, CaptureOffset, DistanceAlpha); + } + + half AbsoluteSpecularMip = ComputeReflectionCaptureMipFromRoughness(Roughness, Frame.ReflectionCubemapMaxMip); #if FEATURE_LEVEL >= FEATURE_LEVEL_SM5 - float4 SpecularIBL = TextureCubeArraySampleLevel(ReflectionCubemap, ReflectionCubemapSampler, MaterialParameters.ReflectionVector, CubemapArrayIndex, AbsoluteSpecularMip); + float4 Sample = TextureCubeArraySampleLevel(ReflectionCubemap, ReflectionCubemapSampler, ProjectedCaptureVector, CubemapArrayIndex, AbsoluteSpecularMip); #else - float4 SpecularIBL = TextureCubeSampleLevel(ReflectionCubemap, ReflectionCubemapSampler, MaterialParameters.ReflectionVector, AbsoluteSpecularMip); + float4 Sample = TextureCubeSampleLevel(ReflectionCubemap, ReflectionCubemapSampler, ProjectedCaptureVector, AbsoluteSpecularMip); #endif + Sample *= DistanceAlpha; + + // Under operator (back to front) + float IndirectSpecularOcclusion = 1.0f; + SpecularIBL.rgb += Sample.rgb * SpecularIBL.a * IndirectSpecularOcclusion; + SpecularIBL.a *= 1 - Sample.a; + } #if ALLOW_STATIC_LIGHTING FLATTEN @@ -93,7 +138,7 @@ half3 GetImageBasedReflectionLighting(FMaterialPixelParameters MaterialParameter { // Normalize for static skylight types which mix with lightmaps bool bNormalize = SkyLightParameters.z < 1 && Frame.UseLightmaps; - float3 SkyLighting = GetSkyLightReflection(MaterialParameters.ReflectionVector, Roughness, bNormalize); + float3 SkyLighting = GetSkyLightReflection(RV, Roughness, bNormalize); FLATTEN if (bNormalize) @@ -126,7 +171,7 @@ half3 GetImageBasedReflectionLighting(FMaterialPixelParameters MaterialParameter RayCast( HZBTexture, HZBSampler, float2(1, 1), - MaterialParameters.WorldPosition_CamRelative, MaterialParameters.ReflectionVector, 0, 0, MaterialParameters.ScreenPosition.w, + MaterialParameters.WorldPosition_CamRelative, RV, 0, 0, MaterialParameters.ScreenPosition.w, 12, StepOffset, HitUVzTime, HCBLevel ); @@ -141,7 +186,7 @@ half3 GetImageBasedReflectionLighting(FMaterialPixelParameters MaterialParameter } #endif - half NoV = saturate(dot(MaterialParameters.WorldNormal, MaterialParameters.CameraVector)); + SpecularColor = EnvBRDFApprox(SpecularColor, Roughness, NoV); float3 SpecularLighting = SpecularIBL.rgb; @@ -158,7 +203,6 @@ half3 GetImageBasedReflectionLighting(FMaterialPixelParameters MaterialParameter return SpecularLighting * SpecularColor; } - #endif #if TRANSLUCENCY_LIGHTING_SURFACE_PERPIXEL @@ -844,6 +888,28 @@ void Main( GBuffer.CustomData.x = ClearCoat; GBuffer.CustomData.y = ClearCoatRoughness; + + #if CLEAR_COAT_BOTTOM_NORMAL + { + float2 oct2 = UnitVectorToOctahedron(GBuffer.WorldNormal); + + #if NUM_MATERIAL_OUTPUTS_CLEARCOATBOTTOMNORMAL > 0 + #if MATERIAL_TANGENTSPACENORMAL + float3 tempnormal = normalize(TransformTangentVectorToWorld( MaterialParameters.TangentToWorld, ClearCoatBottomNormal0(MaterialParameters) )); + #else + float3 tempnormal = ClearCoatBottomNormal0(MaterialParameters); + #endif + + float2 oct1 = UnitVectorToOctahedron(tempnormal); + float2 oct3 = ( (oct1 - oct2) * 0.5 ) + (128.0/255.0); + GBuffer.CustomData.a = oct3.x; + GBuffer.CustomData.z = oct3.y; + #else + GBuffer.CustomData.a = 128.0/255.0; + GBuffer.CustomData.z = 128.0/255.0; + #endif + } + #endif } #elif MATERIAL_SHADINGMODEL_TWOSIDED_FOLIAGE GBuffer.ShadingModelID = SHADINGMODELID_TWOSIDED_FOLIAGE; @@ -925,30 +991,6 @@ void Main( Color += (DiffuseIndirectLighting * EffectiveDiffuseColor + SubsurfaceIndirectLighting * SubsurfaceColor) * MaterialAO; - #if MATERIAL_SHADINGMODEL_CLEAR_COAT - { - const float ClearCoat = GBuffer.CustomData.x; - const float ClearCoatRoughness = GBuffer.CustomData.y; - - // TODO EnvBRDF should have a mask param - //float2 AB = PreIntegratedGF.SampleLevel( PreIntegratedGFSampler, float2( NoV, GBuffer.Roughness ), 0 ).rg; - //Color.rgb *= GBuffer.SpecularColor * AB.x + AB.y * saturate( 50 * GBuffer.SpecularColor.g ) * (1 - ClearCoat); - - float3 N = MaterialParameters.WorldNormal; - float3 V = MaterialParameters.CameraVector; - float NoV = saturate( dot( N, V ) ); - - // F_Schlick - float F0 = 0.04; - float Fc = Pow5( 1 - NoV ); - float F = Fc + (1 - Fc) * F0; - F *= ClearCoat; - - float LayerAttenuation = (1 - F); - - Color += LayerAttenuation * GetImageBasedReflectionLighting(MaterialParameters, GBuffer.Roughness, SpecularColor, IndirectIrradiance); - } - #endif #if SIMPLE_DYNAMIC_LIGHTING // always unshadowed so BiasedNDotL is not needed diff --git a/Engine/Shaders/Common.usf b/Engine/Shaders/Common.usf index 858ff264ce94..b07ea255798d 100644 --- a/Engine/Shaders/Common.usf +++ b/Engine/Shaders/Common.usf @@ -145,6 +145,13 @@ #define ES3_1_PROFILE 1 #define FCOLOR_COMPONENT_SWIZZLE .bgra #define STENCIL_COMPONENT_SWIZZLE .x +#elif METAL_ES2_PROFILE + #define FEATURE_LEVEL FEATURE_LEVEL_ES2 + // @todo metal: remove this and make sure all uses handle METAL_ES2_PROFILE + #undef ES2_PROFILE + #define ES2_PROFILE 1 + #define FCOLOR_COMPONENT_SWIZZLE .bgra + #define STENCIL_COMPONENT_SWIZZLE .x #elif METAL_MRT_PROFILE #define FEATURE_LEVEL FEATURE_LEVEL_SM4 #define FCOLOR_COMPONENT_SWIZZLE .bgra @@ -510,7 +517,7 @@ MaterialFloat PhongShadingPow(MaterialFloat X, MaterialFloat Y) return ClampedPow(X, Y); } -#if FEATURE_LEVEL < FEATURE_LEVEL_ES3_1 +#if FEATURE_LEVEL < FEATURE_LEVEL_ES3_1 && !COMPILER_METAL // DX11 (feature levels >= 10) feature sets natively supports uints in shaders; we just use floats on other platforms. #define uint4 int4 #endif diff --git a/Engine/Shaders/Definitions.usf b/Engine/Shaders/Definitions.usf index 1eb2f864e3b9..b49d42a2d9e0 100644 --- a/Engine/Shaders/Definitions.usf +++ b/Engine/Shaders/Definitions.usf @@ -192,6 +192,10 @@ #define INSTANCED_STEREO 0 #endif +#ifndef CLEAR_COAT_BOTTOM_NORMAL +#define CLEAR_COAT_BOTTOM_NORMAL 0 +#endif + #ifndef TEX_COORD_SCALE_ANALYSIS #define TEX_COORD_SCALE_ANALYSIS 0 #endif diff --git a/Engine/Shaders/GpuSkinVertexFactory.usf b/Engine/Shaders/GpuSkinVertexFactory.usf index 6a4b50cfe27a..9ca653712a0d 100644 --- a/Engine/Shaders/GpuSkinVertexFactory.usf +++ b/Engine/Shaders/GpuSkinVertexFactory.usf @@ -64,7 +64,7 @@ struct FVertexFactoryInput // TangentZ.w contains sign of tangent basis determinant half4 TangentZ : ATTRIBUTE2; -#if FEATURE_LEVEL >= FEATURE_LEVEL_ES3_1 +#if FEATURE_LEVEL >= FEATURE_LEVEL_ES3_1 || COMPILER_METAL uint4 BlendIndices : ATTRIBUTE3; #if GPUSKIN_USE_EXTRA_INFLUENCES uint4 BlendIndicesExtra : ATTRIBUTE14; diff --git a/Engine/Shaders/MaterialTemplate.usf b/Engine/Shaders/MaterialTemplate.usf index a0abb31db707..f8e704c1cdec 100644 --- a/Engine/Shaders/MaterialTemplate.usf +++ b/Engine/Shaders/MaterialTemplate.usf @@ -751,7 +751,7 @@ MaterialFloat2 GetParticleMacroUV(FMaterialPixelParameters Parameters) } #ifndef MOBILE_EMULATION -#define MOBILE_EMULATION ((FEATURE_LEVEL == FEATURE_LEVEL_ES2 || FEATURE_LEVEL == FEATURE_LEVEL_ES3_1) && (!COMPILER_GLSL_ES2 && USE_DEVELOPMENT_SHADERS && !(METAL_PROFILE && MAC))) +#define MOBILE_EMULATION ((FEATURE_LEVEL == FEATURE_LEVEL_ES2 || FEATURE_LEVEL == FEATURE_LEVEL_ES3_1) && (!COMPILER_GLSL_ES2 && USE_DEVELOPMENT_SHADERS && (COMPILER_METAL && MAC))) #endif MaterialFloat4 ProcessMaterialColorTextureLookup(MaterialFloat4 TextureValue) diff --git a/Engine/Shaders/PostProcessAmbient.usf b/Engine/Shaders/PostProcessAmbient.usf index 1732168a2ef2..c8ea02d4eb65 100644 --- a/Engine/Shaders/PostProcessAmbient.usf +++ b/Engine/Shaders/PostProcessAmbient.usf @@ -352,14 +352,14 @@ void MainPS(in noperspective float4 UVAndScreenPos : TEXCOORD0, float4 SvPositio float3 N = GBuffer.WorldNormal; float3 V = -ScreenVector; - float3 R = 2 * dot( V, N ) * N - V; + float3 R0 = 2 * dot( V, N ) * N - V; //float NoV = max( dot(N, V), 1e-5 ); float NoV = saturate( dot(N, V) ); // Point lobe in off-specular peak direction float a = Square( GBuffer.Roughness ); - R = lerp( N, R, (1 - a) * ( sqrt(1 - a) + a ) ); + float3 R = lerp( N, R0, (1 - a) * ( sqrt(1 - a) + a ) ); uint2 Random = ScrambleTEA( PixelPos ); Random.x ^= Frame.Random; @@ -379,17 +379,35 @@ void MainPS(in noperspective float4 UVAndScreenPos : TEXCOORD0, float4 SvPositio // Specular { - float Mip = ComputeCubemapMipFromRoughness( GBuffer.Roughness, AmbientCubemapMipAdjust.w ); - float3 SampleColor = TextureCubeSampleLevel( AmbientCubemap, AmbientCubemapSampler, R, Mip ).rgb; BRANCH if( GBuffer.ShadingModelID == SHADINGMODELID_CLEAR_COAT ) { - float ClearCoat = GBuffer.CustomData.x; - float2 AB = PreIntegratedGF.SampleLevel( PreIntegratedGFSampler, float2( NoV, GBuffer.Roughness ), 0 ).rg; - SpecularContribution += SampleColor * ( GBuffer.SpecularColor * AB.x + AB.y * (1 - ClearCoat) ); + float ClearCoat = GBuffer.CustomData.x; + + #if CLEAR_COAT_BOTTOM_NORMAL + //const float3 ClearCoatUnderNormal = OctahedronToUnitVector((float2(GBuffer.CustomData.a, GBuffer.CustomData.z) * 2) - (256.0/255.0)); + const float2 oct1 = ((float2(GBuffer.CustomData.a, GBuffer.CustomData.z) * 2) - (256.0/255.0)) + UnitVectorToOctahedron(GBuffer.WorldNormal); + const float3 ClearCoatUnderNormal = OctahedronToUnitVector(oct1); + float3 R2 = 2 * dot( V, ClearCoatUnderNormal ) * ClearCoatUnderNormal - V; + + float Mip = ComputeCubemapMipFromRoughness( GBuffer.Roughness, AmbientCubemapMipAdjust.w ); + float3 SampleColor = TextureCubeSampleLevel( AmbientCubemap, AmbientCubemapSampler, R2, Mip ).rgb; + + float2 AB = PreIntegratedGF.SampleLevel( PreIntegratedGFSampler, float2( NoV, GBuffer.Roughness ), 0 ).rg; + SpecularContribution += SampleColor * ( GBuffer.SpecularColor * AB.x + AB.y * (1 - ClearCoat) ); + #else + float Mip = ComputeCubemapMipFromRoughness( GBuffer.Roughness, AmbientCubemapMipAdjust.w ); + float3 SampleColor = TextureCubeSampleLevel( AmbientCubemap, AmbientCubemapSampler, R, Mip ).rgb; + + float2 AB = PreIntegratedGF.SampleLevel( PreIntegratedGFSampler, float2( NoV, GBuffer.Roughness ), 0 ).rg; + SpecularContribution += SampleColor * ( GBuffer.SpecularColor * AB.x + AB.y * (1 - ClearCoat) ); + #endif } else { + float Mip = ComputeCubemapMipFromRoughness( GBuffer.Roughness, AmbientCubemapMipAdjust.w ); + float3 SampleColor = TextureCubeSampleLevel( AmbientCubemap, AmbientCubemapSampler, R, Mip ).rgb; + SpecularContribution += SampleColor * EnvBRDF( GBuffer.SpecularColor, GBuffer.Roughness, NoV ); //SpecularContribution += ApproximateSpecularIBL( Random, GBuffer.SpecularColor, GBuffer.Roughness, GBuffer.WorldNormal, -ScreenVector ); } @@ -401,7 +419,7 @@ void MainPS(in noperspective float4 UVAndScreenPos : TEXCOORD0, float4 SvPositio const float ClearCoatRoughness = GBuffer.CustomData.y; float Mip = ComputeCubemapMipFromRoughness( ClearCoatRoughness, AmbientCubemapMipAdjust.w ); - float3 SampleColor = TextureCubeSampleLevel( AmbientCubemap, AmbientCubemapSampler, R, Mip ).rgb; + float3 SampleColor = TextureCubeSampleLevel( AmbientCubemap, AmbientCubemapSampler, R0, Mip ).rgb; // F_Schlick float F0 = 0.04; diff --git a/Engine/Shaders/PostProcessSelectionOutline.usf b/Engine/Shaders/PostProcessSelectionOutline.usf index 6750ada6faba..a4af1dc45f89 100644 --- a/Engine/Shaders/PostProcessSelectionOutline.usf +++ b/Engine/Shaders/PostProcessSelectionOutline.usf @@ -219,17 +219,17 @@ void MainPS(noperspective float4 UVAndScreenPos : TEXCOORD0, float4 SvPosition : int ScountStep = 2; #if MSAA_SAMPLE_COUNT > 1 int4 StencilScout = int4( - EditorPrimitivesStencil.Load(PixelPos + int2( ScountStep, 0), 0).g, - EditorPrimitivesStencil.Load(PixelPos + int2(-ScountStep, 0), 0).g, - EditorPrimitivesStencil.Load(PixelPos + int2( 0, ScountStep), 0).g, - EditorPrimitivesStencil.Load(PixelPos + int2( 0, -ScountStep), 0).g + EditorPrimitivesStencil.Load(PixelPos + int2( ScountStep, 0), 0) STENCIL_COMPONENT_SWIZZLE, + EditorPrimitivesStencil.Load(PixelPos + int2(-ScountStep, 0), 0) STENCIL_COMPONENT_SWIZZLE, + EditorPrimitivesStencil.Load(PixelPos + int2( 0, ScountStep), 0) STENCIL_COMPONENT_SWIZZLE, + EditorPrimitivesStencil.Load(PixelPos + int2( 0, -ScountStep), 0) STENCIL_COMPONENT_SWIZZLE ); #else int4 StencilScout = int4( - EditorPrimitivesStencil.Load(int3(PixelPos + int2( ScountStep, 0), 0)).g, - EditorPrimitivesStencil.Load(int3(PixelPos + int2(-ScountStep, 0), 0)).g, - EditorPrimitivesStencil.Load(int3(PixelPos + int2( 0, ScountStep), 0)).g, - EditorPrimitivesStencil.Load(int3(PixelPos + int2( 0, -ScountStep), 0)).g + EditorPrimitivesStencil.Load(int3(PixelPos + int2( ScountStep, 0), 0)) STENCIL_COMPONENT_SWIZZLE, + EditorPrimitivesStencil.Load(int3(PixelPos + int2(-ScountStep, 0), 0)) STENCIL_COMPONENT_SWIZZLE, + EditorPrimitivesStencil.Load(int3(PixelPos + int2( 0, ScountStep), 0)) STENCIL_COMPONENT_SWIZZLE, + EditorPrimitivesStencil.Load(int3(PixelPos + int2( 0, -ScountStep), 0)) STENCIL_COMPONENT_SWIZZLE ); #endif int ScoutSum = dot(saturate(StencilScout), 1); diff --git a/Engine/Shaders/ReflectionEnvironmentComputeShaders.usf b/Engine/Shaders/ReflectionEnvironmentComputeShaders.usf index e397259e824c..298624eaf9b9 100644 --- a/Engine/Shaders/ReflectionEnvironmentComputeShaders.usf +++ b/Engine/Shaders/ReflectionEnvironmentComputeShaders.usf @@ -409,7 +409,7 @@ float CountOverlap( float3 WorldPosition ) return Overlap; } -void GatherRadiance(inout float4 Color, float3 WorldPosition, float3 RayDirection, float Roughness, float2 ScreenPosition, float IndirectIrradiance, uint ShadingModelID) +void GatherRadiance(inout float4 Color, float3 WorldPosition, float3 RayDirection, float Roughness, float2 ScreenPosition, float IndirectIrradiance, float NoV, uint ShadingModelID) { // Indirect occlusion from DFAO, which should be applied to reflection captures and skylight specular, but not SSR float IndirectSpecularOcclusion = 1.0f; @@ -419,8 +419,7 @@ void GatherRadiance(inout float4 Color, float3 WorldPosition, float3 RayDirectio float IndirectDiffuseOcclusion; GetDistanceFieldAOSpecularOcclusion(ScreenUV, RayDirection, Roughness, ShadingModelID == SHADINGMODELID_TWOSIDED_FOLIAGE, IndirectSpecularOcclusion, IndirectDiffuseOcclusion); // Apply DFAO to IndirectIrradiance before mixing with indirect specular - IndirectIrradiance *= IndirectDiffuseOcclusion; - + IndirectIrradiance *= IndirectDiffuseOcclusion; #endif float Mip = ComputeReflectionCaptureMipFromRoughness(Roughness, Frame.ReflectionCubemapMaxMip); @@ -444,14 +443,15 @@ void GatherRadiance(inout float4 Color, float3 WorldPosition, float3 RayDirectio #endif float4 CapturePositionAndRadius = ReflectionCapture.PositionAndRadius[CaptureIndex]; - float4 CaptureProperties = ReflectionCapture.CaptureProperties[CaptureIndex]; + float4 CaptureProperties = ReflectionCapture.CaptureProperties[CaptureIndex]; + float3 CaptureVector = WorldPosition - CapturePositionAndRadius.xyz; - float CaptureVectorLength = length(CaptureVector); + float CaptureVectorLength = sqrt(dot(CaptureVector, CaptureVector)); + float NormalizedDistanceToCapture = saturate(CaptureVectorLength / CapturePositionAndRadius.w); BRANCH if (CaptureVectorLength < CapturePositionAndRadius.w) - { - float NormalizedDistanceToCapture = saturate(CaptureVectorLength / CapturePositionAndRadius.w); + { float3 ProjectedCaptureVector = RayDirection; // Fade out based on distance to capture @@ -467,34 +467,7 @@ void GatherRadiance(inout float4 Color, float3 WorldPosition, float3 RayDirectio BRANCH if (CaptureProperties.b > 0) # endif //HAS_SPHERE_CAPTURES { - // Transform the ray into the local space of the box, where it is an AABB with mins at -1 and maxs at 1 - float3 LocalRayStart = mul(float4(WorldPosition, 1), ReflectionCapture.BoxTransform[CaptureIndex]).xyz; - float3 LocalRayDirection = mul(float4(RayDirection, 0), ReflectionCapture.BoxTransform[CaptureIndex]).xyz; - - float3 InvRayDir = rcp(LocalRayDirection); - - //find the ray intersection with each of the 3 planes defined by the minimum extrema. - float3 FirstPlaneIntersections = -InvRayDir - LocalRayStart * InvRayDir; - //find the ray intersection with each of the 3 planes defined by the maximum extrema. - float3 SecondPlaneIntersections = InvRayDir - LocalRayStart * InvRayDir; - //get the furthest of these intersections along the ray - float3 FurthestPlaneIntersections = max(FirstPlaneIntersections, SecondPlaneIntersections); - - //clamp the intersections to be between RayOrigin and RayEnd on the ray - float Intersection = min(FurthestPlaneIntersections.x, min(FurthestPlaneIntersections.y, FurthestPlaneIntersections.z)); - - // Compute the reprojected vector - float3 IntersectPosition = WorldPosition + Intersection * RayDirection; - ProjectedCaptureVector = IntersectPosition - (CapturePositionAndRadius.xyz + ReflectionCapture.CaptureOffset[CaptureIndex].xyz); - - // Compute the distance from the receiving pixel to the box for masking - // Apply local to world scale to take scale into account without transforming back to world space - // Shrink the box by the transition distance (BoxScales.w) so that the fade happens inside the box influence area - float4 BoxScales = ReflectionCapture.BoxScales[CaptureIndex]; - float BoxDistance = ComputeDistanceFromBoxToPoint(-(BoxScales.xyz - .5f * BoxScales.w), BoxScales.xyz - .5f * BoxScales.w, LocalRayStart * BoxScales.xyz); - - // Setup a fade based on receiver distance to the box, hides the box influence shape - DistanceAlpha = 1.0 - smoothstep(0, .7f * BoxScales.w, BoxDistance); + ProjectedCaptureVector = GetLookupVectorForBoxCapture(RayDirection, WorldPosition, CapturePositionAndRadius, ReflectionCapture.BoxTransform[CaptureIndex], ReflectionCapture.BoxScales[CaptureIndex], ReflectionCapture.CaptureOffset[CaptureIndex].xyz, DistanceAlpha); } #endif //HAS_BOX_CAPTURES @@ -504,33 +477,7 @@ void GatherRadiance(inout float4 Color, float3 WorldPosition, float3 RayDirectio else # endif //HAS_BOX_CAPTURES { - float ProjectionSphereRadius = CapturePositionAndRadius.w; - float SphereRadiusSquared = ProjectionSphereRadius * ProjectionSphereRadius; - - float3 LocalPosition = WorldPosition - CapturePositionAndRadius.xyz; - float LocalPositionSqr = dot(LocalPosition, LocalPosition); - - // Find the intersection between the ray along the reflection vector and the capture's sphere - float3 QuadraticCoef; - QuadraticCoef.x = 1; - QuadraticCoef.y = dot(RayDirection, LocalPosition); - QuadraticCoef.z = LocalPositionSqr - SphereRadiusSquared; - - float Determinant = QuadraticCoef.y * QuadraticCoef.y - QuadraticCoef.z; - - // Only continue if the ray intersects the sphere - //if (Determinant >= 0) - { - float FarIntersection = sqrt(Determinant) - QuadraticCoef.y; - - float3 LocalIntersectionPosition = LocalPosition + FarIntersection * RayDirection; - ProjectedCaptureVector = LocalIntersectionPosition - ReflectionCapture.CaptureOffset[CaptureIndex].xyz; - // Note: some compilers don't handle smoothstep min > max (this was 1, .6) - //DistanceAlpha = 1.0 - smoothstep(.6, 1, NormalizedDistanceToCapture); - - float x = saturate( 2.5 * NormalizedDistanceToCapture - 1.5 ); - DistanceAlpha = 1 - x*x*(3 - 2*x); - } + ProjectedCaptureVector = GetLookupVectorForSphereCapture(RayDirection, WorldPosition, CapturePositionAndRadius, NormalizedDistanceToCapture, ReflectionCapture.CaptureOffset[CaptureIndex].xyz, DistanceAlpha); } #endif //HAS_SPHERE_CAPTURES #else @@ -636,61 +583,82 @@ void ReflectionEnvironmentTiledDeferredMain( BRANCH if( GBuffer.ShadingModelID != SHADINGMODELID_UNLIT && GBuffer.ShadingModelID != SHADINGMODELID_HAIR ) - { - if( GBuffer.ShadingModelID == SHADINGMODELID_CLEAR_COAT ) - { - const float ClearCoat = GBuffer.CustomData.x; - const float ClearCoatRoughness = GBuffer.CustomData.y; + { - GBuffer.Roughness = lerp( GBuffer.Roughness, ClearCoatRoughness, ClearCoat ); - GBuffer.SpecularColor = lerp( GBuffer.SpecularColor, 0.04, ClearCoat ); - } float3 N = GBuffer.WorldNormal; float3 V = -CameraToPixel; float3 R = 2 * dot( V, N ) * N - V; - float NoV = saturate( dot( N, V ) ); // Point lobe in off-specular peak direction float a = Square( GBuffer.Roughness ); R = lerp( N, R, (1 - a) * ( sqrt(1 - a) + a ) ); - #if 1 +#if 1 // Note: this texture may also contain planar reflections float4 SSR = ScreenSpaceReflections.Load( int3(PixelPos, 0) ); Color.rgb = SSR.rgb; Color.a = 1 - SSR.a; - #endif - - float AO = ScreenSpaceData.AmbientOcclusion; - float SpecularOcclusion = saturate( pow( NoV + AO, a ) - 1 + AO ); - - Color.a *= SpecularOcclusion; - - GatherRadiance(Color, WorldPosition, R, GBuffer.Roughness, ScreenPosition, IndirectIrradiance, GBuffer.ShadingModelID); - - Color.rgb *= EnvBRDF( GBuffer.SpecularColor, GBuffer.Roughness, NoV ); - } - -#if 0 - { - float3 N = GBuffer.WorldNormal; - float3 V = -CameraToPixel; - float3 L = Frame.DirectionalLightDirection; - float NoL = saturate( dot( N, L ) ); - - Color.rgb += Frame.DirectionalLightColor.rgb * SurfaceShading( GBuffer, GBuffer.Roughness, 1, L, V, N, 1, uint2(0,0) ); - - float3 SurfaceLighting = SurfaceShading( GBuffer, GBuffer.Roughness, 1, L, V, N, 1, uint2(0,0) ) * NoL; - float3 SubsurfaceLighting = SubsurfaceShading( GBuffer, L, V, N, 1, uint2(0,0) ); - //float3 SurfaceLighting = StandardShading( GBuffer, GBuffer.Roughness, 1, L, V, N, 1 ) * NoL; - //float3 SubsurfaceLighting = 0; - - Color.rgb += Frame.DirectionalLightColor.rgb * ( SurfaceLighting + SubsurfaceLighting ); - } #endif + if( GBuffer.ShadingModelID == SHADINGMODELID_CLEAR_COAT ) + { + const float ClearCoat = GBuffer.CustomData.x; + Color = lerp( Color, float4(0,0,0,1), ClearCoat ); + +#if CLEAR_COAT_BOTTOM_NORMAL + const float2 oct1 = ((float2(GBuffer.CustomData.a, GBuffer.CustomData.z) * 2) - (256.0/255.0)) + UnitVectorToOctahedron(GBuffer.WorldNormal); + const float3 ClearCoatUnderNormal = OctahedronToUnitVector(oct1); + + const float3 BottomEffectiveNormal = ClearCoatUnderNormal; + R = 2 * dot( V, ClearCoatUnderNormal ) * ClearCoatUnderNormal - V; +#endif + } + + float AO = ScreenSpaceData.AmbientOcclusion; + float RoughnessSq = GBuffer.Roughness * GBuffer.Roughness; + float SpecularOcclusion = GetSpecularOcclusion(NoV, RoughnessSq, AO); + + R = GetOffSpecularPeakReflectionDir(N, R, GBuffer.Roughness); + //bottom for clearcoat or the only reflection. + GatherRadiance(Color, WorldPosition, R, GBuffer.Roughness, ScreenPosition, IndirectIrradiance, NoV, GBuffer.ShadingModelID); + + BRANCH + if( GBuffer.ShadingModelID == SHADINGMODELID_CLEAR_COAT ) + { + const float ClearCoat = GBuffer.CustomData.x; + const float ClearCoatRoughness = GBuffer.CustomData.y; + + // TODO EnvBRDF should have a mask param + float2 AB = PreIntegratedGF.SampleLevel( PreIntegratedGFSampler, float2( NoV, GBuffer.Roughness ), 0 ).rg; + Color.rgb *= GBuffer.SpecularColor * AB.x + AB.y * saturate( 50 * GBuffer.SpecularColor.g ) * (1 - ClearCoat); + + // F_Schlick + float F0 = 0.04; + float Fc = Pow5( 1 - NoV ); + float F = Fc + (1 - Fc) * F0; + F *= ClearCoat; + + float LayerAttenuation = (1 - F); + Color.rgb *= LayerAttenuation; + Color.a = F; + + + Color.rgb += SSR.rgb * F; + Color.a *= 1 - SSR.a; + + Color.a *= SpecularOcclusion; + + float3 TopLayerR = 2 * dot( V, N ) * N - V; + GatherRadiance(Color, WorldPosition, TopLayerR, ClearCoatRoughness, ScreenPosition, IndirectIrradiance, NoV, GBuffer.ShadingModelID); + } + else + { + Color.rgb *= EnvBRDF( GBuffer.SpecularColor, GBuffer.Roughness, NoV ); + } + } + // Only write to the buffer for threads inside the view BRANCH if (all(DispatchThreadId.xy < ViewDimensions.zw)) diff --git a/Engine/Shaders/ReflectionEnvironmentShaders.usf b/Engine/Shaders/ReflectionEnvironmentShaders.usf index e699abe94fd9..48d55ca82b0a 100644 --- a/Engine/Shaders/ReflectionEnvironmentShaders.usf +++ b/Engine/Shaders/ReflectionEnvironmentShaders.usf @@ -361,65 +361,14 @@ void StandardDeferredReflectionPS( //@todo - find a way to share this code with the compute shader version - #if SPHERE_CAPTURE - float3 RayDirection = ReflectionVector; - float ProjectionSphereRadius = CapturePositionAndRadius.w * 1.2f; - float SphereRadiusSquared = ProjectionSphereRadius * ProjectionSphereRadius; - - float3 ReceiverToSphereCenter = WorldPosition - CapturePositionAndRadius.xyz; - float ReceiverToSphereCenterSq = dot(ReceiverToSphereCenter, ReceiverToSphereCenter); - + #if SPHERE_CAPTURE float3 CaptureVector = WorldPosition - CapturePositionAndRadius.xyz; float CaptureVectorLength = sqrt(dot(CaptureVector, CaptureVector)); float NormalizedDistanceToCapture = saturate(CaptureVectorLength / CapturePositionAndRadius.w); - // Find the intersection between the ray along the reflection vector and the capture's sphere - float3 QuadraticCoef; - QuadraticCoef.x = 1; - QuadraticCoef.y = 2 * dot(RayDirection, ReceiverToSphereCenter); - QuadraticCoef.z = ReceiverToSphereCenterSq - SphereRadiusSquared; - - float Determinant = QuadraticCoef.y * QuadraticCoef.y - 4 * QuadraticCoef.z; - - BRANCH - // Only continue if the ray intersects the sphere - if (Determinant >= 0) - { - float FarIntersection = (sqrt(Determinant) - QuadraticCoef.y) * 0.5; - - float3 LocalIntersectionPosition = ReceiverToSphereCenter + FarIntersection * RayDirection; - ProjectedCaptureVector = LocalIntersectionPosition - CaptureOffset; - - // Fade out based on distance to capture - DistanceAlpha = 1.0 - smoothstep(.6, 1, NormalizedDistanceToCapture); - } + ProjectedCaptureVector = GetLookupVectorForSphereCapture(ReflectionVector, WorldPosition, CapturePositionAndRadius, NormalizedDistanceToCapture, CaptureOffset, DistanceAlpha); #elif BOX_CAPTURE - float3 RayDirection = ReflectionVector * CapturePositionAndRadius.w * 2; - - // Transform the ray into the local space of the box, where it is an AABB with mins at -1 and maxs at 1 - float3 LocalRayStart = mul(float4(WorldPosition, 1), CaptureBoxTransform).xyz; - float3 LocalRayDirection = mul(RayDirection, (float3x3)CaptureBoxTransform); - - // Intersections.y is the intersection with the far side of the box - float2 Intersections = LineBoxIntersect(LocalRayStart, LocalRayStart + LocalRayDirection, -1, 1); - - { - // Compute the reprojected vector - float3 IntersectPosition = WorldPosition + Intersections.y * RayDirection; - ProjectedCaptureVector = IntersectPosition - (CapturePositionAndRadius.xyz + CaptureOffset); - - // Compute the distance from the receiving pixel to the box for masking - // Apply local to world scale to take scale into account without transforming back to world space - // Shrink the box by the transition distance (BoxScales.w) so that the fade happens inside the box influence area - float4 BoxScales = CaptureBoxScales; - float BoxDistance = ComputeDistanceFromBoxToPoint(-(BoxScales.xyz - .5f * BoxScales.w), BoxScales.xyz - .5f * BoxScales.w, LocalRayStart * BoxScales.xyz); - - // Setup a fade based on receiver distance to the box, hides the box influence shape - float BoxDistanceAlpha = 1.0 - smoothstep(0, .7f * BoxScales.w, BoxDistance); - // Setup a fade based on reflection ray intersection distance, hides the discontinuity between rays that just barely - float RayDistanceAlpha = smoothstep(0, BoxScales.w, Intersections.y * CapturePositionAndRadius.w * 2); - DistanceAlpha = BoxDistanceAlpha * RayDistanceAlpha; - } + ProjectedCaptureVector = GetLookupVectorForBoxCapture(ReflectionVector, WorldPosition, CapturePositionAndRadius, CaptureBoxTransform, CaptureBoxScales, CaptureOffset, DistanceAlpha); #endif BRANCH @@ -464,20 +413,13 @@ void ReflectionApplyPS( // Only light pixels marked as lit if( GBuffer.ShadingModelID > 0 && GBuffer.ShadingModelID != SHADINGMODELID_HAIR ) { - if( GBuffer.ShadingModelID == SHADINGMODELID_CLEAR_COAT ) - { - const float ClearCoat = GBuffer.CustomData.x; - const float ClearCoatRoughness = GBuffer.CustomData.y; - - GBuffer.Roughness = lerp( GBuffer.Roughness, ClearCoatRoughness, ClearCoat ); - GBuffer.SpecularColor = lerp( GBuffer.SpecularColor, 0.04, ClearCoat ); - } - // TODO if SpecularColor and Roughness were in same texture would remove 2 fetches float3 V = -normalize( mul( float4(UVAndScreenPos.zw, 1, 0), View.ScreenToWorld ).xyz ); - float NoV = saturate( dot( GBuffer.WorldNormal, V ) ); + float3 N = GBuffer.WorldNormal; + float NoV = saturate( dot(N, V ) ); float3 SpecularColor = EnvBRDF( GBuffer.SpecularColor, GBuffer.Roughness, NoV ); - float3 ReflectionVector = reflect(-V, GBuffer.WorldNormal); + float3 ReflectionVector = reflect(-V, N); + ReflectionVector = GetOffSpecularPeakReflectionDir(N, ReflectionVector, GBuffer.Roughness); float IndirectIrradiance = GBuffer.IndirectIrradiance; float AO = GBuffer.GBufferAO * ScreenSpaceData.AmbientOcclusion; @@ -516,7 +458,8 @@ void ReflectionApplyPS( #endif #endif -#if APPLY_SSR +#if 1 + // Note: this texture may also contain planar reflections float4 SSR = Texture2DSample( ScreenSpaceReflectionsTexture, ScreenSpaceReflectionsSampler, UV ); SpecularLighting.rgb = SSR.rgb + SpecularLighting.rgb * (1 - SSR.a); SpecularLighting.a *= 1 - SSR.a; @@ -528,11 +471,51 @@ void ReflectionApplyPS( BRANCH if (SpecularLighting.a > .001f) - { + { + float3 SkyLighting = float3(1,1,1); + // Normalize for static skylight types which mix with lightmaps bool bNormalize = SkyLightParameters.z < 1 && Frame.UseLightmaps > 0 && !ALLOW_STATIC_LIGHTING; - float3 SkyLighting = GetSkyLightReflectionSupportingBlend(ReflectionVector, GBuffer.Roughness, bNormalize); - SkyLighting *= SpecularColor; + BRANCH + if( GBuffer.ShadingModelID == SHADINGMODELID_CLEAR_COAT ) + { +#if CLEAR_COAT_BOTTOM_NORMAL + const float2 oct1 = ((float2(GBuffer.CustomData.a, GBuffer.CustomData.z) * 2) - (256.0 / 255.0)) + UnitVectorToOctahedron(GBuffer.WorldNormal); + const float3 ClearCoatUnderNormal = OctahedronToUnitVector(oct1); + + const float3 BottomEffectiveNormal = ClearCoatUnderNormal; + ReflectionVector = 2 * dot(V, ClearCoatUnderNormal) * ClearCoatUnderNormal - V; +#endif + + SkyLighting = GetSkyLightReflectionSupportingBlend(ReflectionVector, GBuffer.Roughness, bNormalize); + SkyLighting *= SpecularColor; + + const float ClearCoat = GBuffer.CustomData.x; + const float ClearCoatRoughness = GBuffer.CustomData.y; + + // F_Schlick + float F0 = 0.04; + float Fc = Pow5( 1 - NoV ); + float F = Fc + (1 - Fc) * F0; + F *= ClearCoat; + + float LayerAttenuation = (1 - F); + SkyLighting.rgb *= LayerAttenuation; + + #if APPLY_SSR + F *= 1 - SSR.a; + #endif + + float3 TopLayerR = 2 * dot(V, GBuffer.WorldNormal) * N - V; + float3 SampleColor = GetSkyLightReflectionSupportingBlend(TopLayerR, ClearCoatRoughness, bNormalize); + SkyLighting += SampleColor * F; + } + else + { + SkyLighting = GetSkyLightReflectionSupportingBlend(ReflectionVector, GBuffer.Roughness, bNormalize); + SkyLighting *= SpecularColor; + + } float DirectionalOcclusion = ScreenSpaceData.DirectionalOcclusion.g; SkyLighting *= DirectionalOcclusion; diff --git a/Engine/Shaders/ReflectionEnvironmentShared.usf b/Engine/Shaders/ReflectionEnvironmentShared.usf index 21d267a1068c..6d834ef6b352 100644 --- a/Engine/Shaders/ReflectionEnvironmentShared.usf +++ b/Engine/Shaders/ReflectionEnvironmentShared.usf @@ -120,3 +120,82 @@ float3 GetSkySHDiffuseSimple(float3 Normal) // max to not get negative colors, maybe we can optimize to use saturate() and scale later or clamp this way: saturate(A/100)*100 return max(0, Intermediate0); } + + +// Point lobe in off-specular peak direction +float3 GetOffSpecularPeakReflectionDir(float3 Normal, float3 ReflectionVector, float Roughness) +{ + float a = Square(Roughness); + return lerp( Normal, ReflectionVector, (1 - a) * ( sqrt(1 - a) + a ) ); +} + +float GetSpecularOcclusion(float NoV, float RoughnessSq, float AO) +{ + return saturate( pow( NoV + AO, RoughnessSq ) - 1 + AO ); +} + +float3 GetLookupVectorForBoxCapture(float3 ReflectionVector, float3 WorldPosition, float4 BoxCapturePositionAndRadius, float4x4 BoxTransform, float4 BoxScales, float3 LocalCaptureOffset, out float DistanceAlpha) +{ + // Transform the ray into the local space of the box, where it is an AABB with mins at -1 and maxs at 1 + float3 LocalRayStart = mul(float4(WorldPosition, 1), BoxTransform).xyz; + float3 LocalRayDirection = mul(float4(ReflectionVector, 0), BoxTransform).xyz; + + float3 InvRayDir = rcp(LocalRayDirection); + + //find the ray intersection with each of the 3 planes defined by the minimum extrema. + float3 FirstPlaneIntersections = -InvRayDir - LocalRayStart * InvRayDir; + //find the ray intersection with each of the 3 planes defined by the maximum extrema. + float3 SecondPlaneIntersections = InvRayDir - LocalRayStart * InvRayDir; + //get the furthest of these intersections along the ray + float3 FurthestPlaneIntersections = max(FirstPlaneIntersections, SecondPlaneIntersections); + + //clamp the intersections to be between RayOrigin and RayEnd on the ray + float Intersection = min(FurthestPlaneIntersections.x, min(FurthestPlaneIntersections.y, FurthestPlaneIntersections.z)); + + // Compute the reprojected vector + float3 IntersectPosition = WorldPosition + Intersection * ReflectionVector; + float3 ProjectedCaptureVector = IntersectPosition - (BoxCapturePositionAndRadius.xyz + LocalCaptureOffset); + + // Compute the distance from the receiving pixel to the box for masking + // Apply local to world scale to take scale into account without transforming back to world space + // Shrink the box by the transition distance (BoxScales.w) so that the fade happens inside the box influence area + float BoxDistance = ComputeDistanceFromBoxToPoint(-(BoxScales.xyz - .5f * BoxScales.w), BoxScales.xyz - .5f * BoxScales.w, LocalRayStart * BoxScales.xyz); + + // Setup a fade based on receiver distance to the box, hides the box influence shape + DistanceAlpha = 1.0 - smoothstep(0, .7f * BoxScales.w, BoxDistance); + + return ProjectedCaptureVector; +} + +float3 GetLookupVectorForSphereCapture(float3 ReflectionVector, float3 WorldPosition, float4 SphereCapturePositionAndRadius, float NormalizedDistanceToCapture, float3 LocalCaptureOffset, out float DistanceAlpha) +{ + float3 ProjectedCaptureVector = ReflectionVector; + float ProjectionSphereRadius = SphereCapturePositionAndRadius.w; + float SphereRadiusSquared = ProjectionSphereRadius * ProjectionSphereRadius; + + float3 LocalPosition = WorldPosition - SphereCapturePositionAndRadius.xyz; + float LocalPositionSqr = dot(LocalPosition, LocalPosition); + + // Find the intersection between the ray along the reflection vector and the capture's sphere + float3 QuadraticCoef; + QuadraticCoef.x = 1; + QuadraticCoef.y = dot(ReflectionVector, LocalPosition); + QuadraticCoef.z = LocalPositionSqr - SphereRadiusSquared; + + float Determinant = QuadraticCoef.y * QuadraticCoef.y - QuadraticCoef.z; + + // Only continue if the ray intersects the sphere + //if (Determinant >= 0) + { + float FarIntersection = sqrt(Determinant) - QuadraticCoef.y; + + float3 LocalIntersectionPosition = LocalPosition + FarIntersection * ReflectionVector; + ProjectedCaptureVector = LocalIntersectionPosition - LocalCaptureOffset; + // Note: some compilers don't handle smoothstep min > max (this was 1, .6) + //DistanceAlpha = 1.0 - smoothstep(.6, 1, NormalizedDistanceToCapture); + + float x = saturate( 2.5 * NormalizedDistanceToCapture - 1.5 ); + DistanceAlpha = 1 - x*x*(3 - 2*x); + } + return ProjectedCaptureVector; +} \ No newline at end of file diff --git a/Engine/Shaders/ShadingModels.usf b/Engine/Shaders/ShadingModels.usf index aa585a780a5f..43db5a91096c 100644 --- a/Engine/Shaders/ShadingModels.usf +++ b/Engine/Shaders/ShadingModels.usf @@ -105,6 +105,32 @@ float3 ClearCoatShading( FGBufferData GBuffer, float3 LobeRoughness, float3 Lobe float LayerAttenuation = (1 - F); + + #if CLEAR_COAT_BOTTOM_NORMAL + { + //const float3 ClearCoatUnderNormal = OctahedronToUnitVector((float2(GBuffer.CustomData.a, GBuffer.CustomData.z) * 2) - (256.0/255.0)); + const float2 oct1 = ((float2(GBuffer.CustomData.a, GBuffer.CustomData.z) * 2) - (256.0/255.0)) + UnitVectorToOctahedron(GBuffer.WorldNormal); + const float3 ClearCoatUnderNormal = OctahedronToUnitVector(oct1); + //float CNoL = saturate( dot(ClearCoatUnderNormal, L) ); + //float CNoV = saturate( dot(ClearCoatUnderNormal, V) ); + float CNoH = saturate( dot(ClearCoatUnderNormal, H) ); + + float D2 = D_GGX(LobeRoughness[1], CNoH ) * LobeEnergy[1]; + float Vis2 = Vis_Schlick( LobeRoughness[1], NoV, NoL ); + //float3 F2 = F_Schlick( GBuffer.SpecularColor, VoH ); + float3 F2 = saturate( 50.0 * GBuffer.SpecularColor.g ) * Fc + (1 - Fc) * GBuffer.SpecularColor; + + //Optional term taking into account Basic NdotL response of bottom normal. Not important for metallic which is the most common clearcoat case. Not energy conserving. + //float3 Fr2 = Diffuse_Lambert( GBuffer.DiffuseColor ) * CNoL + (D2 * Vis2) * F2; + + float3 Fr2 = Diffuse_Lambert( GBuffer.DiffuseColor ) + (D2 * Vis2) * F2; + + return Fr1 + Fr2 * LayerAttenuation; + //return float3(2,0,0); + //return ClearCoatUnderNormal; + } + #endif + // Generalized microfacet specular float D2 = D_GGX( LobeRoughness[1], NoH ) * LobeEnergy[1]; float Vis2 = Vis_Schlick( LobeRoughness[1], NoV, NoL ); diff --git a/Engine/Source/Developer/Apple/MetalShaderFormat/Private/MetalBackend.cpp b/Engine/Source/Developer/Apple/MetalShaderFormat/Private/MetalBackend.cpp index 2c2365aa2161..d3cd989f6a91 100644 --- a/Engine/Source/Developer/Apple/MetalShaderFormat/Private/MetalBackend.cpp +++ b/Engine/Source/Developer/Apple/MetalShaderFormat/Private/MetalBackend.cpp @@ -3185,10 +3185,10 @@ bool FMetalCodeBackend::GenerateMain(EHlslShaderFrequency Frequency, const char* return true; } -FMetalCodeBackend::FMetalCodeBackend(unsigned int InHlslCompileFlags, EHlslCompileTarget InTarget) : +FMetalCodeBackend::FMetalCodeBackend(unsigned int InHlslCompileFlags, EHlslCompileTarget InTarget, bool bInDesktop) : FCodeBackend(InHlslCompileFlags, HCT_FeatureLevelES3_1) { - bIsDesktop = (InTarget == HCT_FeatureLevelSM4 || InTarget == HCT_FeatureLevelSM5); + bIsDesktop = bInDesktop; } void FMetalLanguageSpec::SetupLanguageIntrinsics(_mesa_glsl_parse_state* State, exec_list* ir) diff --git a/Engine/Source/Developer/Apple/MetalShaderFormat/Private/MetalBackend.h b/Engine/Source/Developer/Apple/MetalShaderFormat/Private/MetalBackend.h index 9b8276c8ad03..c260236d19a0 100644 --- a/Engine/Source/Developer/Apple/MetalShaderFormat/Private/MetalBackend.h +++ b/Engine/Source/Developer/Apple/MetalShaderFormat/Private/MetalBackend.h @@ -44,7 +44,7 @@ struct FBuffers; // Generates Metal compliant code from IR tokens struct FMetalCodeBackend : public FCodeBackend { - FMetalCodeBackend(unsigned int InHlslCompileFlags, EHlslCompileTarget InTarget); + FMetalCodeBackend(unsigned int InHlslCompileFlags, EHlslCompileTarget InTarget, bool bInDesktop); virtual char* GenerateCode(struct exec_list* ir, struct _mesa_glsl_parse_state* ParseState, EHlslShaderFrequency Frequency) override; diff --git a/Engine/Source/Developer/Apple/MetalShaderFormat/Private/MetalShaderCompiler.cpp b/Engine/Source/Developer/Apple/MetalShaderFormat/Private/MetalShaderCompiler.cpp index 0f48d569b479..125e88937231 100644 --- a/Engine/Source/Developer/Apple/MetalShaderFormat/Private/MetalShaderCompiler.cpp +++ b/Engine/Source/Developer/Apple/MetalShaderFormat/Private/MetalShaderCompiler.cpp @@ -366,28 +366,15 @@ static void BuildMetalShaderOutput( MetalPath = MetalToolsPath + TEXT("/metal"); } - // metal commandlines - FString MathMode = Header.bFastMath ? TEXT("-ffast-math") : TEXT("-fno-fast-math"); - FString Params = FString::Printf(TEXT("%s -Wno-null-character %s %s -o %s"), *MathMode, Standard, *InputFilename, *ObjFilename); - FPlatformProcess::ExecProcess( *MetalPath, *Params, &ReturnCode, &Results, &Errors ); - - // handle compile error - if (ReturnCode != 0 || IFileManager::Get().FileSize(*ObjFilename) <= 0) + if (IFileManager::Get().FileSize(*MetalPath) > 0) { - FShaderCompilerError* Error = new(OutErrors) FShaderCompilerError(); - Error->ErrorFile = InputFilename; - Error->ErrorLineString = TEXT("0"); - Error->StrippedErrorMessage = Results + Errors; - bSucceeded = false; - } - else - { - Params = FString::Printf(TEXT("r %s %s"), *ArFilename, *ObjFilename); - FString MetalArPath = MetalToolsPath + TEXT("/metal-ar"); - FPlatformProcess::ExecProcess( *MetalArPath, *Params, &ReturnCode, &Results, &Errors ); + // metal commandlines + FString MathMode = Header.bFastMath ? TEXT("-ffast-math") : TEXT("-fno-fast-math"); + FString Params = FString::Printf(TEXT("%s -Wno-null-character %s %s -o %s"), *MathMode, Standard, *InputFilename, *ObjFilename); + FPlatformProcess::ExecProcess( *MetalPath, *Params, &ReturnCode, &Results, &Errors ); // handle compile error - if (ReturnCode != 0 || IFileManager::Get().FileSize(*ArFilename) <= 0) + if (ReturnCode != 0 || IFileManager::Get().FileSize(*ObjFilename) <= 0) { FShaderCompilerError* Error = new(OutErrors) FShaderCompilerError(); Error->ErrorFile = InputFilename; @@ -397,12 +384,12 @@ static void BuildMetalShaderOutput( } else { - Params = FString::Printf(TEXT("-o %s %s"), *OutputFilename, *ArFilename); - FString MetalLibPath = MetalToolsPath + TEXT("/metallib"); - FPlatformProcess::ExecProcess( *MetalLibPath, *Params, &ReturnCode, &Results, &Errors ); - + Params = FString::Printf(TEXT("r %s %s"), *ArFilename, *ObjFilename); + FString MetalArPath = MetalToolsPath + TEXT("/metal-ar"); + FPlatformProcess::ExecProcess( *MetalArPath, *Params, &ReturnCode, &Results, &Errors ); + // handle compile error - if (ReturnCode != 0 || IFileManager::Get().FileSize(*OutputFilename) <= 0) + if (ReturnCode != 0 || IFileManager::Get().FileSize(*ArFilename) <= 0) { FShaderCompilerError* Error = new(OutErrors) FShaderCompilerError(); Error->ErrorFile = InputFilename; @@ -412,31 +399,53 @@ static void BuildMetalShaderOutput( } else { - bCompileAtRuntime = false; - - // Write out the header and compiled shader code - FMemoryWriter Ar(ShaderOutput.ShaderCode.GetWriteAccess(), true); - uint8 PrecompiledFlag = 1; - Ar << PrecompiledFlag; - Ar << Header; + Params = FString::Printf(TEXT("-o %s %s"), *OutputFilename, *ArFilename); + FString MetalLibPath = MetalToolsPath + TEXT("/metallib"); + FPlatformProcess::ExecProcess( *MetalLibPath, *Params, &ReturnCode, &Results, &Errors ); + + // handle compile error + if (ReturnCode != 0 || IFileManager::Get().FileSize(*OutputFilename) <= 0) + { + FShaderCompilerError* Error = new(OutErrors) FShaderCompilerError(); + Error->ErrorFile = InputFilename; + Error->ErrorLineString = TEXT("0"); + Error->StrippedErrorMessage = Results + Errors; + bSucceeded = false; + } + else + { + bCompileAtRuntime = false; + + // Write out the header and compiled shader code + FMemoryWriter Ar(ShaderOutput.ShaderCode.GetWriteAccess(), true); + uint8 PrecompiledFlag = 1; + Ar << PrecompiledFlag; + Ar << Header; - // load output - TArray CompiledShader; - FFileHelper::LoadFileToArray(CompiledShader, *OutputFilename); - - // jam it into the output bytes - Ar.Serialize(CompiledShader.GetData(), CompiledShader.Num()); - - // store data we can pickup later with ShaderCode.FindOptionalData('n'), could be removed for shipping - ShaderOutput.ShaderCode.AddOptionalData('n', TCHAR_TO_UTF8(*ShaderInput.GenerateShaderName())); + // load output + TArray CompiledShader; + FFileHelper::LoadFileToArray(CompiledShader, *OutputFilename); + + // jam it into the output bytes + Ar.Serialize(CompiledShader.GetData(), CompiledShader.Num()); + + // store data we can pickup later with ShaderCode.FindOptionalData('n'), could be removed for shipping + ShaderOutput.ShaderCode.AddOptionalData('n', TCHAR_TO_UTF8(*ShaderInput.GenerateShaderName())); - ShaderOutput.NumInstructions = 0; - ShaderOutput.NumTextureSamplers = Header.Bindings.NumSamplers; - ShaderOutput.bSucceeded = true; - bSucceeded = true; + ShaderOutput.NumInstructions = 0; + ShaderOutput.NumTextureSamplers = Header.Bindings.NumSamplers; + ShaderOutput.bSucceeded = true; + bSucceeded = true; + } } } } + else + { + UE_LOG(LogMetalShaderCompiler, Warning, TEXT("Could not find offline 'metal' shader compiler - falling back to slower online compiled text shaders.")); + bCompileAtRuntime = true; + bSucceeded = true; + } } #else // do not compile on non-Windows @@ -533,8 +542,10 @@ void CompileShader_Metal(const FShaderCompilerInput& Input,FShaderCompilerOutput static FName NAME_SF_METAL_SM4(TEXT("SF_METAL_SM4")); static FName NAME_SF_METAL_SM5(TEXT("SF_METAL_SM5")); static FName NAME_SF_METAL_MACES3_1(TEXT("SF_METAL_MACES3_1")); + static FName NAME_SF_METAL_MACES2(TEXT("SF_METAL_MACES2")); TCHAR const* Standard = TEXT("-std=ios-metal1.0"); + bool bIsDesktop = false; if (Input.ShaderFormat == NAME_SF_METAL) { @@ -544,12 +555,21 @@ void CompileShader_Metal(const FShaderCompilerInput& Input,FShaderCompilerOutput { AdditionalDefines.SetDefine(TEXT("METAL_MRT_PROFILE"), 1); } + else if (Input.ShaderFormat == NAME_SF_METAL_MACES2) + { + AdditionalDefines.SetDefine(TEXT("METAL_ES2_PROFILE"), 1); + AdditionalDefines.SetDefine(TEXT("FORCE_FLOATS"), 1); // Force floats to avoid radr://24884199 & radr://24884860 + Standard = TEXT("-std=osx-metal1.1"); + MetalCompilerTarget = HCT_FeatureLevelES2; + bIsDesktop = true; + } else if (Input.ShaderFormat == NAME_SF_METAL_MACES3_1) { AdditionalDefines.SetDefine(TEXT("METAL_PROFILE"), 1); AdditionalDefines.SetDefine(TEXT("FORCE_FLOATS"), 1); // Force floats to avoid radr://24884199 & radr://24884860 Standard = TEXT("-std=osx-metal1.1"); MetalCompilerTarget = HCT_FeatureLevelES3_1; + bIsDesktop = true; } else if (Input.ShaderFormat == NAME_SF_METAL_SM4) { @@ -557,6 +577,7 @@ void CompileShader_Metal(const FShaderCompilerInput& Input,FShaderCompilerOutput AdditionalDefines.SetDefine(TEXT("USING_VERTEX_SHADER_LAYER"), 1); Standard = TEXT("-std=osx-metal1.1"); MetalCompilerTarget = HCT_FeatureLevelSM4; + bIsDesktop = true; } else if (Input.ShaderFormat == NAME_SF_METAL_SM5) { @@ -564,6 +585,7 @@ void CompileShader_Metal(const FShaderCompilerInput& Input,FShaderCompilerOutput AdditionalDefines.SetDefine(TEXT("USING_VERTEX_SHADER_LAYER"), 1); Standard = TEXT("-std=osx-metal1.1"); MetalCompilerTarget = HCT_FeatureLevelSM5; + bIsDesktop = true; } else { @@ -654,7 +676,7 @@ void CompileShader_Metal(const FShaderCompilerInput& Input,FShaderCompilerOutput // Required as we added the RemoveUniformBuffersFromSource() function (the cross-compiler won't be able to interpret comments w/o a preprocessor) CCFlags &= ~HLSLCC_NoPreprocess; - FMetalCodeBackend MetalBackEnd(CCFlags, MetalCompilerTarget); + FMetalCodeBackend MetalBackEnd(CCFlags, MetalCompilerTarget, bIsDesktop); FMetalLanguageSpec MetalLanguageSpec; int32 Result = 0; diff --git a/Engine/Source/Developer/Apple/MetalShaderFormat/Private/MetalShaderFormat.cpp b/Engine/Source/Developer/Apple/MetalShaderFormat/Private/MetalShaderFormat.cpp index d299e76ee0fa..5482ae0a1635 100644 --- a/Engine/Source/Developer/Apple/MetalShaderFormat/Private/MetalShaderFormat.cpp +++ b/Engine/Source/Developer/Apple/MetalShaderFormat/Private/MetalShaderFormat.cpp @@ -13,6 +13,7 @@ static FName NAME_SF_METAL_MRT(TEXT("SF_METAL_MRT")); static FName NAME_SF_METAL_SM4(TEXT("SF_METAL_SM4")); static FName NAME_SF_METAL_SM5(TEXT("SF_METAL_SM5")); static FName NAME_SF_METAL_MACES3_1(TEXT("SF_METAL_MACES3_1")); +static FName NAME_SF_METAL_MACES2(TEXT("SF_METAL_MACES2")); class FMetalShaderFormat : public IShaderFormat { @@ -55,10 +56,11 @@ public: OutFormats.Add(NAME_SF_METAL_SM4); OutFormats.Add(NAME_SF_METAL_SM5); OutFormats.Add(NAME_SF_METAL_MACES3_1); + OutFormats.Add(NAME_SF_METAL_MACES2); } virtual void CompileShader(FName Format, const struct FShaderCompilerInput& Input, struct FShaderCompilerOutput& Output,const FString& WorkingDirectory) const { - check(Format == NAME_SF_METAL || Format == NAME_SF_METAL_MRT || Format == NAME_SF_METAL_SM4 || Format == NAME_SF_METAL_SM5 || Format == NAME_SF_METAL_MACES3_1); + check(Format == NAME_SF_METAL || Format == NAME_SF_METAL_MRT || Format == NAME_SF_METAL_SM4 || Format == NAME_SF_METAL_SM5 || Format == NAME_SF_METAL_MACES3_1 || Format == NAME_SF_METAL_MACES2); CompileShader_Metal(Input, Output, WorkingDirectory); } }; diff --git a/Engine/Source/Developer/AssetTools/AssetTools.Build.cs b/Engine/Source/Developer/AssetTools/AssetTools.Build.cs index 8d1b23d1b9a9..79d06f3d4aed 100644 --- a/Engine/Source/Developer/AssetTools/AssetTools.Build.cs +++ b/Engine/Source/Developer/AssetTools/AssetTools.Build.cs @@ -44,6 +44,7 @@ public class AssetTools : ModuleRules "Kismet", "MainFrame", "MaterialEditor", + "MessageLog", "Persona", "FontEditor", "SoundCueEditor", @@ -67,6 +68,7 @@ public class AssetTools : ModuleRules "ActorPickerMode", "MainFrame", "MaterialEditor", + "MessageLog", "Persona", "FontEditor", "SoundCueEditor", diff --git a/Engine/Source/Developer/AssetTools/Private/AssetTools.cpp b/Engine/Source/Developer/AssetTools/Private/AssetTools.cpp index 9dac55997c5a..dc25e919308c 100644 --- a/Engine/Source/Developer/AssetTools/Private/AssetTools.cpp +++ b/Engine/Source/Developer/AssetTools/Private/AssetTools.cpp @@ -1741,7 +1741,7 @@ void FAssetTools::MigratePackages_ReportConfirmed(TArray ConfirmedPacka } } - FMessageLog MigrateLog("AssetRegistry"); + FMessageLog MigrateLog("AssetTools"); FText LogMessage = FText::FromString(TEXT("Content migration completed successfully!")); EMessageSeverity::Type Severity = EMessageSeverity::Info; if ( CopyErrors.Len() > 0 || SourceControlErrors.Len() > 0 ) diff --git a/Engine/Source/Developer/AssetTools/Private/AssetToolsModule.cpp b/Engine/Source/Developer/AssetTools/Private/AssetToolsModule.cpp index 86df1a88f4f7..ac477608dc68 100644 --- a/Engine/Source/Developer/AssetTools/Private/AssetToolsModule.cpp +++ b/Engine/Source/Developer/AssetTools/Private/AssetToolsModule.cpp @@ -3,6 +3,7 @@ #include "AssetToolsPrivatePCH.h" #include "AssetToolsModule.h" #include "AssetToolsConsoleCommands.h" +#include "MessageLogModule.h" IMPLEMENT_MODULE( FAssetToolsModule, AssetTools ); DEFINE_LOG_CATEGORY(LogAssetTools); @@ -11,6 +12,12 @@ void FAssetToolsModule::StartupModule() { AssetTools = new FAssetTools(); ConsoleCommands = new FAssetToolsConsoleCommands(*this); + + // create a message log for the asset tools to use + FMessageLogModule& MessageLogModule = FModuleManager::LoadModuleChecked("MessageLog"); + FMessageLogInitializationOptions InitOptions; + InitOptions.bShowPages = true; + MessageLogModule.RegisterLogListing("AssetTools", NSLOCTEXT("AssetTools", "AssetToolsLogLabel", "Asset Tools"), InitOptions); } void FAssetToolsModule::ShutdownModule() @@ -26,6 +33,13 @@ void FAssetToolsModule::ShutdownModule() delete ConsoleCommands; ConsoleCommands = NULL; } + + if (FModuleManager::Get().IsModuleLoaded("MessageLog")) + { + // unregister message log + FMessageLogModule& MessageLogModule = FModuleManager::GetModuleChecked("MessageLog"); + MessageLogModule.UnregisterLogListing("AssetTools"); + } } IAssetTools& FAssetToolsModule::Get() const diff --git a/Engine/Source/Developer/AssetTools/Private/AssetTypeActions/AssetTypeActions_ClassTypeBase.h b/Engine/Source/Developer/AssetTools/Private/AssetTypeActions/AssetTypeActions_ClassTypeBase.h index 018a6812a065..2b5dd5d9a864 100644 --- a/Engine/Source/Developer/AssetTools/Private/AssetTypeActions/AssetTypeActions_ClassTypeBase.h +++ b/Engine/Source/Developer/AssetTools/Private/AssetTypeActions/AssetTypeActions_ClassTypeBase.h @@ -10,6 +10,8 @@ class IClassTypeActions; class ASSETTOOLS_API FAssetTypeActions_ClassTypeBase : public FAssetTypeActions_Base { public: + virtual bool CanLocalize() const override { return false; } + /** Get the class type actions for this asset */ virtual TWeakPtr GetClassTypeActions(const FAssetData& AssetData) const = 0; diff --git a/Engine/Source/Developer/AssetTools/Private/AssetTypeActions/AssetTypeActions_Enum.h b/Engine/Source/Developer/AssetTools/Private/AssetTypeActions/AssetTypeActions_Enum.h index ba34a19d4134..7dda53259da0 100644 --- a/Engine/Source/Developer/AssetTools/Private/AssetTypeActions/AssetTypeActions_Enum.h +++ b/Engine/Source/Developer/AssetTools/Private/AssetTypeActions/AssetTypeActions_Enum.h @@ -12,6 +12,7 @@ public: virtual FColor GetTypeColor() const override { return FColor(255, 200, 200); } virtual UClass* GetSupportedClass() const override { return UUserDefinedEnum::StaticClass(); } virtual uint32 GetCategories() override { return EAssetTypeCategories::Blueprint; } + virtual bool CanLocalize() const override { return false; } virtual void OpenAssetEditor( const TArray& InObjects, TSharedPtr EditWithinLevelEditor = TSharedPtr() ) override; }; diff --git a/Engine/Source/Developer/AssetTools/Private/AssetTypeActions/AssetTypeActions_Redirector.h b/Engine/Source/Developer/AssetTools/Private/AssetTypeActions/AssetTypeActions_Redirector.h index 55579c4558f6..fa547daf3058 100644 --- a/Engine/Source/Developer/AssetTools/Private/AssetTypeActions/AssetTypeActions_Redirector.h +++ b/Engine/Source/Developer/AssetTools/Private/AssetTypeActions/AssetTypeActions_Redirector.h @@ -13,6 +13,7 @@ public: virtual void GetActions( const TArray& InObjects, FMenuBuilder& MenuBuilder ) override; virtual void AssetsActivated( const TArray& InObjects, EAssetTypeActivationMethod::Type ActivationType ) override; virtual uint32 GetCategories() override { return EAssetTypeCategories::Misc; } + virtual bool CanLocalize() const override { return false; } private: /** Handler for when FindTarget is selected */ diff --git a/Engine/Source/Developer/AssetTools/Private/AssetTypeActions/AssetTypeActions_Struct.h b/Engine/Source/Developer/AssetTools/Private/AssetTypeActions/AssetTypeActions_Struct.h index 1625d0138f96..39531a18e2cf 100644 --- a/Engine/Source/Developer/AssetTools/Private/AssetTypeActions/AssetTypeActions_Struct.h +++ b/Engine/Source/Developer/AssetTools/Private/AssetTypeActions/AssetTypeActions_Struct.h @@ -12,6 +12,7 @@ public: virtual FColor GetTypeColor() const override { return FColor(103, 206, 218); } virtual UClass* GetSupportedClass() const override { return UUserDefinedStruct::StaticClass(); } virtual uint32 GetCategories() override { return EAssetTypeCategories::Blueprint; } + virtual bool CanLocalize() const override { return false; } virtual FText GetAssetDescription(const FAssetData& AssetData) const override; virtual void OpenAssetEditor( const TArray& InObjects, TSharedPtr EditWithinLevelEditor = TSharedPtr() ) override; diff --git a/Engine/Source/Developer/AssetTools/Private/AssetTypeActions/AssetTypeActions_World.h b/Engine/Source/Developer/AssetTools/Private/AssetTypeActions/AssetTypeActions_World.h index f7a59d1373fc..b8b14fa6d7d4 100644 --- a/Engine/Source/Developer/AssetTools/Private/AssetTypeActions/AssetTypeActions_World.h +++ b/Engine/Source/Developer/AssetTools/Private/AssetTypeActions/AssetTypeActions_World.h @@ -12,5 +12,6 @@ public: virtual bool HasActions ( const TArray& InObjects ) const override { return false; } virtual void OpenAssetEditor( const TArray& InObjects, TSharedPtr EditWithinLevelEditor = TSharedPtr() ) override; virtual uint32 GetCategories() override { return EAssetTypeCategories::Basic; } + virtual bool CanLocalize() const override { return false; } virtual class UThumbnailInfo* GetThumbnailInfo(UObject* Asset) const override; }; \ No newline at end of file diff --git a/Engine/Source/Developer/AssetTools/Public/AssetTypeActions_Base.h b/Engine/Source/Developer/AssetTools/Public/AssetTypeActions_Base.h index 9d990c518b74..d2e07c5b5e87 100644 --- a/Engine/Source/Developer/AssetTools/Public/AssetTypeActions_Base.h +++ b/Engine/Source/Developer/AssetTools/Public/AssetTypeActions_Base.h @@ -50,6 +50,11 @@ public: return true; } + virtual bool CanLocalize() const override + { + return true; + } + virtual bool CanMerge() const override { return false; diff --git a/Engine/Source/Developer/AssetTools/Public/IAssetTypeActions.h b/Engine/Source/Developer/AssetTools/Public/IAssetTypeActions.h index bc563fd25037..3df49a8c9038 100644 --- a/Engine/Source/Developer/AssetTools/Public/IAssetTypeActions.h +++ b/Engine/Source/Developer/AssetTools/Public/IAssetTypeActions.h @@ -62,6 +62,9 @@ public: /** Returns true if this class can be used as a filter in the content browser */ virtual bool CanFilter() = 0; + /** Returns true if this class can be localized */ + virtual bool CanLocalize() const = 0; + /** Returns true if this class can be merged (either manually or automatically) */ virtual bool CanMerge() const = 0; diff --git a/Engine/Source/Developer/BlueprintCompilerCppBackend/Private/BlueprintCompilerCppBackendUtils.cpp b/Engine/Source/Developer/BlueprintCompilerCppBackend/Private/BlueprintCompilerCppBackendUtils.cpp index ae4171dddeeb..4c15b548c7e3 100644 --- a/Engine/Source/Developer/BlueprintCompilerCppBackend/Private/BlueprintCompilerCppBackendUtils.cpp +++ b/Engine/Source/Developer/BlueprintCompilerCppBackend/Private/BlueprintCompilerCppBackendUtils.cpp @@ -1323,18 +1323,29 @@ FString FEmitHelper::AccessInaccessibleProperty(FEmitterLocalContext& EmitterCon { check(Property); const FString PropertyLocalName = GenerateGetPropertyByName(EmitterContext, Property); + const UBoolProperty* BoolProperty = Cast(Property); + if (bGetter && BoolProperty) + { + return FString::Printf(TEXT("(((UBoolProperty*)%s)->GetPropertyValue_InContainer(%s(%s), %d))") + , *PropertyLocalName + , *ContextAdressOp + , *ContextStr + , StaticArrayIdx); + } + if (BoolProperty && !BoolProperty->IsNativeBool()) + { + UE_LOG(LogK2Compiler, Error, TEXT("AccessInaccessiblePropertyUsingOffset - bitfield %s"), *GetPathNameSafe(Property)); + } const uint32 CppTemplateTypeFlags = EPropertyExportCPPFlags::CPPF_CustomTypeName | EPropertyExportCPPFlags::CPPF_NoConst | EPropertyExportCPPFlags::CPPF_NoRef | EPropertyExportCPPFlags::CPPF_NoStaticArray | EPropertyExportCPPFlags::CPPF_BlueprintCppBackend; - const FString TypeDeclaration = EmitterContext.ExportCppDeclaration(Property, EExportedDeclaration::Parameter, CppTemplateTypeFlags, true); - const FString Result = FString::Printf(TEXT("(*(%s->ContainerPtrToValuePtr<%s>(%s(%s), %d)))") + const FString TypeDeclaration = EmitterContext.ExportCppDeclaration(Property, EExportedDeclaration::Member, CppTemplateTypeFlags, true); + return FString::Printf(TEXT("(*(%s->ContainerPtrToValuePtr<%s>(%s(%s), %d)))") , *PropertyLocalName , *TypeDeclaration , *ContextAdressOp , *ContextStr , StaticArrayIdx); - const UBoolProperty* BoolProperty = Cast(Property); - return (bGetter && BoolProperty && !BoolProperty->IsNativeBool()) ? FString::Printf(TEXT("(0 != (%s))"), *Result) : Result; } namespace HelperWithoutEditorOnlyMembers diff --git a/Engine/Source/Developer/BlueprintCompilerCppBackend/Private/BlueprintCompilerCppBackendValueHelper.cpp b/Engine/Source/Developer/BlueprintCompilerCppBackend/Private/BlueprintCompilerCppBackendValueHelper.cpp index 77406699b724..611a86f967cf 100644 --- a/Engine/Source/Developer/BlueprintCompilerCppBackend/Private/BlueprintCompilerCppBackendValueHelper.cpp +++ b/Engine/Source/Developer/BlueprintCompilerCppBackend/Private/BlueprintCompilerCppBackendValueHelper.cpp @@ -48,7 +48,7 @@ void FEmitDefaultValueHelper::OuterGenerate(FEmitterLocalContext& Context FString PathToMember; UBlueprintGeneratedClass* PropertyOwnerAsBPGC = Cast(Property->GetOwnerClass()); UScriptStruct* PropertyOwnerAsScriptStruct = Cast(Property->GetOwnerStruct()); - const bool bNoexportProperty = PropertyOwnerAsScriptStruct + const bool bNoExportProperty = PropertyOwnerAsScriptStruct && PropertyOwnerAsScriptStruct->IsNative() && (PropertyOwnerAsScriptStruct->StructFlags & STRUCT_NoExport) // && !PropertyOwnerAsScriptStruct->GetBoolMetaData(TEXT("BlueprintType")) @@ -62,11 +62,25 @@ void FEmitDefaultValueHelper::OuterGenerate(FEmitterLocalContext& Context PathToMember = FString::Printf(TEXT("FUnconvertedWrapper__%s(%s).GetRef__%s()"), *FEmitHelper::GetCppName(PropertyOwnerAsBPGC), *ContainerStr , *UnicodeToCPPIdentifier(Property->GetName(), false, nullptr)); } - else if (bNoexportProperty || Property->HasAnyPropertyFlags(CPF_NativeAccessSpecifierPrivate) || (!bAllowProtected && Property->HasAnyPropertyFlags(CPF_NativeAccessSpecifierProtected))) + else if (bNoExportProperty || Property->HasAnyPropertyFlags(CPF_NativeAccessSpecifierPrivate) || (!bAllowProtected && Property->HasAnyPropertyFlags(CPF_NativeAccessSpecifierProtected))) { + const UBoolProperty* BoolProperty = Cast(Property); + const bool bBietfield = BoolProperty && !BoolProperty->IsNativeBool(); const FString OperatorStr = (EPropertyAccessOperator::Dot == AccessOperator) ? TEXT("&") : TEXT(""); const FString ContainerStr = (EPropertyAccessOperator::None == AccessOperator) ? TEXT("this") : OuterPath; - const FString GetPtrStr = bNoexportProperty + if (bBietfield) + { + const FString PropertyLocalName = FEmitHelper::GenerateGetPropertyByName(Context, Property); + const FString ValueStr = Context.ExportTextItem(Property, Property->ContainerPtrToValuePtr(DataContainer, ArrayIndex)); + Context.AddLine(FString::Printf(TEXT("(((UBoolProperty*)%s)->SetPropertyValue_InContainer(%s(%s), %s, %d));") + , *PropertyLocalName + , *OperatorStr + , *ContainerStr + , *ValueStr + , ArrayIndex)); + continue; + } + const FString GetPtrStr = bNoExportProperty ? FEmitHelper::AccessInaccessiblePropertyUsingOffset(Context, Property, ContainerStr, OperatorStr, ArrayIndex) : FEmitHelper::AccessInaccessibleProperty(Context, Property, ContainerStr, OperatorStr, ArrayIndex, false); PathToMember = Context.GenerateUniqueLocalName(); @@ -80,9 +94,12 @@ void FEmitDefaultValueHelper::OuterGenerate(FEmitterLocalContext& Context const FString ArrayPost = bStaticArray ? FString::Printf(TEXT("[%d]"), ArrayIndex) : TEXT(""); PathToMember = FString::Printf(TEXT("%s%s%s%s"), *OuterPath, *AccessOperatorStr, *FEmitHelper::GetCppName(Property), *ArrayPost); } - const uint8* ValuePtr = Property->ContainerPtrToValuePtr(DataContainer, ArrayIndex); - const uint8* DefaultValuePtr = OptionalDefaultDataContainer ? Property->ContainerPtrToValuePtr(OptionalDefaultDataContainer, ArrayIndex) : nullptr; - InnerGenerate(Context, Property, PathToMember, ValuePtr, DefaultValuePtr); + + { + const uint8* ValuePtr = Property->ContainerPtrToValuePtr(DataContainer, ArrayIndex); + const uint8* DefaultValuePtr = OptionalDefaultDataContainer ? Property->ContainerPtrToValuePtr(OptionalDefaultDataContainer, ArrayIndex) : nullptr; + InnerGenerate(Context, Property, PathToMember, ValuePtr, DefaultValuePtr); + } } } } @@ -476,14 +493,35 @@ struct FNonativeComponentData bool bSetNativeCreationMethod; /** Socket/Bone that Component might attach to */ FName AttachToName; + bool bIsRoot; FNonativeComponentData() : ComponentTemplate(nullptr) , ObjectToCompare(nullptr) , bSetNativeCreationMethod(false) + , bIsRoot(false) { } + bool HandledAsSpecialProperty(FEmitterLocalContext& Context, const UProperty* Property) + { + static const FName RelativeLocationName(TEXT("RelativeLocation")); + static const FName RelativeRotationName(TEXT("RelativeRotation")); + + // skip relative location and rotation. THey are ignored for root components created from scs (and they probably should be reset by scs editor). + if (bIsRoot && (Property->GetOuter() == USceneComponent::StaticClass())) + { + UProperty* RelativeLocationProperty = USceneComponent::StaticClass()->FindPropertyByName(RelativeLocationName); + UProperty* RelativeRotationProperty = USceneComponent::StaticClass()->FindPropertyByName(RelativeRotationName); + if ((Property == RelativeLocationProperty) || (Property == RelativeRotationProperty)) + { + return true; + } + } + + return false; + } + void EmitProperties(FEmitterLocalContext& Context) { ensure(!NativeVariablePropertyName.IsEmpty()); @@ -495,19 +533,21 @@ struct FNonativeComponentData if (!ParentVariableName.IsEmpty()) { const FString SocketName = (AttachToName == NAME_None) ? FString() : FString::Printf(TEXT(", TEXT(\"%s\")"), *AttachToName.ToString()); - Context.AddLine(FString::Printf(TEXT("%s->AttachToComponent(%s, FAttachmentTransformRules::KeepRelativeTransform, %s);"), *NativeVariablePropertyName, *ParentVariableName, *SocketName)); + Context.AddLine(FString::Printf(TEXT("%s->AttachToComponent(%s, FAttachmentTransformRules::KeepRelativeTransform %s);"), *NativeVariablePropertyName, *ParentVariableName, *SocketName)); // AttachTo is called first in case some properties will be overridden. } UClass* ComponentClass = ComponentTemplate->GetClass(); for (auto Property : TFieldRange(ComponentClass)) { - FEmitDefaultValueHelper::OuterGenerate(Context, Property, NativeVariablePropertyName - , reinterpret_cast(ComponentTemplate) - , reinterpret_cast(ObjectToCompare) - , FEmitDefaultValueHelper::EPropertyAccessOperator::Pointer); + if (!HandledAsSpecialProperty(Context, Property)) + { + FEmitDefaultValueHelper::OuterGenerate(Context, Property, NativeVariablePropertyName + , reinterpret_cast(ComponentTemplate) + , reinterpret_cast(ObjectToCompare) + , FEmitDefaultValueHelper::EPropertyAccessOperator::Pointer); + } } - } void EmitForcedPostLoad(FEmitterLocalContext& Context) @@ -551,7 +591,9 @@ FString FEmitDefaultValueHelper::HandleNonNativeComponent(FEmitterLocalContext& FNonativeComponentData NonativeComponentData; NonativeComponentData.NativeVariablePropertyName = NativeVariablePropertyName; NonativeComponentData.ComponentTemplate = ComponentTemplate; - + USCS_Node* RootComponentNode = nullptr; + Node->GetSCS()->GetSceneRootComponentTemplate(&RootComponentNode); + NonativeComponentData.bIsRoot = RootComponentNode == Node; UClass* ComponentClass = ComponentTemplate->GetClass(); check(ComponentClass != nullptr); @@ -964,6 +1006,16 @@ void FEmitDefaultValueHelper::GenerateConstructor(FEmitterLocalContext& Context) for (auto& ComponentToInit : ComponentsToInit) { ComponentToInit.EmitProperties(Context); + + if (Cast(ComponentToInit.ComponentTemplate)) + { + Context.AddLine(FString::Printf(TEXT("if(!%s->IsTemplate())"), *ComponentToInit.NativeVariablePropertyName)); + Context.AddLine(TEXT("{")); + Context.IncreaseIndent(); + Context.AddLine(FString::Printf(TEXT("%s->BodyInstance.FixupData(%s);"), *ComponentToInit.NativeVariablePropertyName, *ComponentToInit.NativeVariablePropertyName)); + Context.DecreaseIndent(); + Context.AddLine(TEXT("}")); + } } } @@ -983,20 +1035,6 @@ void FEmitDefaultValueHelper::GenerateConstructor(FEmitterLocalContext& Context) // TODO: this mechanism could be required by other instanced subobjects. Context.CurrentCodeType = FEmitterLocalContext::EGeneratedCodeType::Regular; Context.ResetPropertiesForInaccessibleStructs(); - if (BPGC->IsChildOf() && ComponentsToInit.Num()) - { - Context.Header.AddLine(TEXT("virtual void FixComponentsFromDynamicClass() override;")); - Context.AddLine(FString::Printf(TEXT("void %s::FixComponentsFromDynamicClass()"), *CppClassName)); - Context.AddLine(TEXT("{")); - Context.IncreaseIndent(); - Context.AddLine(TEXT("Super::FixComponentsFromDynamicClass();")); - for (auto& ComponentToInit : ComponentsToInit) - { - ComponentToInit.EmitForcedPostLoad(Context); - } - Context.DecreaseIndent(); - Context.AddLine(TEXT("}")); - } Context.ResetPropertiesForInaccessibleStructs(); Context.AddLine(FString::Printf(TEXT("void %s::PostLoadSubobjects(FObjectInstancingGraph* OuterInstanceGraph)"), *CppClassName)); diff --git a/Engine/Source/Developer/BlueprintNativeCodeGen/Private/BlueprintNativeCodeGenModule.cpp b/Engine/Source/Developer/BlueprintNativeCodeGen/Private/BlueprintNativeCodeGenModule.cpp index 09953c6ef21f..cf97d1d57ddb 100644 --- a/Engine/Source/Developer/BlueprintNativeCodeGen/Private/BlueprintNativeCodeGenModule.cpp +++ b/Engine/Source/Developer/BlueprintNativeCodeGen/Private/BlueprintNativeCodeGenModule.cpp @@ -217,6 +217,11 @@ void FBlueprintNativeCodeGenModule::Initialize(const FNativeCodeGenInitData& Ini Manifests.Add(FString(*Platform.Key), TUniquePtr(new FBlueprintNativeCodeGenManifest(NativizationCookControllerImpl::DefaultPluginName, OutputPath))); TargetPlatformNames.Add(Platform.Key); + + // Clear source code folder + const FString SourceCodeDir = GetManifest(*Platform.Key).GetTargetPaths().PluginSourceDir(); + UE_LOG(LogBlueprintCodeGen, Log, TEXT("Clear nativized source code directory: %s"), *SourceCodeDir); + IFileManager::Get().DeleteDirectory(*SourceCodeDir, false, true); } FillTargetedForReplacementQuery(); diff --git a/Engine/Source/Developer/Mac/MacTargetPlatform/Private/GenericMacTargetPlatform.h b/Engine/Source/Developer/Mac/MacTargetPlatform/Private/GenericMacTargetPlatform.h index 86e60963204a..895acffdbe98 100644 --- a/Engine/Source/Developer/Mac/MacTargetPlatform/Private/GenericMacTargetPlatform.h +++ b/Engine/Source/Developer/Mac/MacTargetPlatform/Private/GenericMacTargetPlatform.h @@ -148,6 +148,8 @@ return TSuper::SupportsFeature(Feature); OutFormats.AddUnique(NAME_SF_METAL_SM5); static FName NAME_SF_METAL_MACES3_1(TEXT("SF_METAL_MACES3_1")); OutFormats.AddUnique(NAME_SF_METAL_MACES3_1); + static FName NAME_SF_METAL_MACES2(TEXT("SF_METAL_MACES2")); + OutFormats.AddUnique(NAME_SF_METAL_MACES2); } #endif } diff --git a/Engine/Source/Developer/SourceControl/Private/SourceControlModule.cpp b/Engine/Source/Developer/SourceControl/Private/SourceControlModule.cpp index 2e0c6aaf1bba..a81e98e8ae19 100644 --- a/Engine/Source/Developer/SourceControl/Private/SourceControlModule.cpp +++ b/Engine/Source/Developer/SourceControl/Private/SourceControlModule.cpp @@ -172,8 +172,6 @@ void FSourceControlModule::OnSourceControlDialogClosed(const TSharedRef bTemporarilyDisabled = false; #if WITH_EDITOR - GetMutableDefault()->CheckSourceControlCompatability(); - FString NewProvider = CurrentSourceControlProvider->GetName().ToString(); if( FEngineAnalytics::IsAvailable() && !ActiveProviderName.Equals( NewProvider, ESearchCase::IgnoreCase )) { diff --git a/Engine/Source/Editor/AnimGraph/Classes/AnimStateNodeBase.h b/Engine/Source/Editor/AnimGraph/Classes/AnimStateNodeBase.h index 14d7bf64fcd5..2ac37f7a5159 100644 --- a/Engine/Source/Editor/AnimGraph/Classes/AnimStateNodeBase.h +++ b/Engine/Source/Editor/AnimGraph/Classes/AnimStateNodeBase.h @@ -9,6 +9,9 @@ class UAnimStateNodeBase : public UEdGraphNode { GENERATED_UCLASS_BODY() + virtual void Serialize(FArchive& Ar) override; + virtual void PostLoad() override; + // UEdGraphNode interface virtual void PostPasteNode() override; virtual UObject* GetJumpTargetForDoubleClick() const override; diff --git a/Engine/Source/Editor/AnimGraph/Private/AnimGraphNode_RotationMultiplier.cpp b/Engine/Source/Editor/AnimGraph/Private/AnimGraphNode_RotationMultiplier.cpp index df9be806ab57..b512e4c75e2b 100644 --- a/Engine/Source/Editor/AnimGraph/Private/AnimGraphNode_RotationMultiplier.cpp +++ b/Engine/Source/Editor/AnimGraph/Private/AnimGraphNode_RotationMultiplier.cpp @@ -14,7 +14,7 @@ UAnimGraphNode_RotationMultiplier::UAnimGraphNode_RotationMultiplier(const FObje FText UAnimGraphNode_RotationMultiplier::GetControllerDescription() const { - return LOCTEXT("ApplyPercentageOfRotation", "Apply a percentage of Rotation"); + return LOCTEXT("ApplyPercentageOfRotation", "Apply a Percentage of Rotation"); } FText UAnimGraphNode_RotationMultiplier::GetTooltipText() const diff --git a/Engine/Source/Editor/AnimGraph/Private/AnimGraphNode_TwistCorrectiveNode.cpp b/Engine/Source/Editor/AnimGraph/Private/AnimGraphNode_TwistCorrectiveNode.cpp index e2617f37ca8c..886deeee81da 100644 --- a/Engine/Source/Editor/AnimGraph/Private/AnimGraphNode_TwistCorrectiveNode.cpp +++ b/Engine/Source/Editor/AnimGraph/Private/AnimGraphNode_TwistCorrectiveNode.cpp @@ -16,7 +16,7 @@ UAnimGraphNode_TwistCorrectiveNode::UAnimGraphNode_TwistCorrectiveNode(const FOb FText UAnimGraphNode_TwistCorrectiveNode::GetTooltipText() const { - return LOCTEXT("UAnimGraphNode_TwistCorrectiveNode_ToolTip", "Drives the transform of a bone or morph target using the transform of another bone"); + return LOCTEXT("UAnimGraphNode_TwistCorrectiveNode_ToolTip", "Drives curve value (of usually morph target) using the transform of delta angle between base and twist frame to the direction of twist plane. "); } FText UAnimGraphNode_TwistCorrectiveNode::GetNodeTitle(ENodeTitleType::Type TitleType) const diff --git a/Engine/Source/Editor/AnimGraph/Private/AnimPreviewInstance.cpp b/Engine/Source/Editor/AnimGraph/Private/AnimPreviewInstance.cpp index 911eff5cb9f9..1432d912309b 100644 --- a/Engine/Source/Editor/AnimGraph/Private/AnimPreviewInstance.cpp +++ b/Engine/Source/Editor/AnimGraph/Private/AnimPreviewInstance.cpp @@ -191,7 +191,7 @@ void FAnimPreviewInstanceProxy::RefreshCurveBoneControllers() { // go through all curves and see if it has Transform Curve // if so, find what bone that belong to and create BoneMOdifier for them - UAnimSequence* CurrentSequence = Cast(GetCurrentAsset()); + UAnimSequence* CurrentSequence = Cast(CurrentAsset); CurveBoneControllers.Empty(); @@ -243,7 +243,7 @@ void FAnimPreviewInstanceProxy::RefreshCurveBoneControllers() void FAnimPreviewInstanceProxy::UpdateCurveController() { // evaluate the curve data first - UAnimSequenceBase* CurrentSequence = Cast(GetCurrentAsset()); + UAnimSequenceBase* CurrentSequence = Cast(CurrentAsset); if (CurrentSequence && GetSkeleton()) { @@ -302,7 +302,7 @@ void FAnimPreviewInstanceProxy::SetKeyImplementation(const FCompactPose& PreCont { #if WITH_EDITOR // evaluate the curve data first - UAnimSequence* CurrentSequence = Cast(GetCurrentAsset()); + UAnimSequence* CurrentSequence = Cast(CurrentAsset); UDebugSkelMeshComponent* Component = Cast (GetSkelMeshComponent()); if(CurrentSequence && GetSkeleton() && Component && Component->SkeletalMesh) @@ -400,7 +400,7 @@ void UAnimPreviewInstance::NativeInitializeAnimation() FAnimPreviewInstanceProxy& Proxy = GetProxyOnGameThread(); // Cache our play state from the previous animation otherwise set to play - bool bCachedIsPlaying = (Proxy.GetCurrentAsset() != NULL) ? Proxy.IsPlaying() : true; + bool bCachedIsPlaying = (CurrentAsset != nullptr) ? Proxy.IsPlaying() : true; Super::NativeInitializeAnimation(); @@ -447,15 +447,15 @@ void UAnimPreviewInstance::SetSkeletalControlAlpha(float InSkeletalControlAlpha) UAnimSequence* UAnimPreviewInstance::GetAnimSequence() { - return Cast(GetCurrentAsset()); + return Cast(CurrentAsset); } void UAnimPreviewInstance::RestartMontage(UAnimMontage* Montage, FName FromSection) { - FAnimPreviewInstanceProxy& Proxy = GetProxyOnGameThread(); - - if (Montage == Proxy.GetCurrentAsset()) + if (Montage == CurrentAsset) { + FAnimPreviewInstanceProxy& Proxy = GetProxyOnGameThread(); + MontagePreviewType = EMPT_Normal; // since this is preview, we would like not to blend in // just hard stop here @@ -477,7 +477,7 @@ void UAnimPreviewInstance::SetAnimationAsset(UAnimationAsset* NewAsset, bool bIs Proxy.GetRequiredBones().SetUseSourceData(false); Super::SetAnimationAsset(NewAsset, bIsLooping, InPlayRate); - RootMotionMode = Cast(Proxy.GetCurrentAsset()) != NULL ? ERootMotionMode::RootMotionFromMontagesOnly : ERootMotionMode::RootMotionFromEverything; + RootMotionMode = Cast(CurrentAsset) != nullptr ? ERootMotionMode::RootMotionFromMontagesOnly : ERootMotionMode::RootMotionFromEverything; // should re sync up curve bone controllers from new asset Proxy.RefreshCurveBoneControllers(); @@ -488,7 +488,7 @@ void UAnimPreviewInstance::MontagePreview_SetLooping(bool bIsLooping) FAnimPreviewInstanceProxy& Proxy = GetProxyOnGameThread(); Proxy.SetLooping(bIsLooping); - if (UAnimMontage* Montage = Cast(Proxy.GetCurrentAsset())) + if (UAnimMontage* Montage = Cast(CurrentAsset)) { switch (MontagePreviewType) { @@ -514,7 +514,7 @@ void UAnimPreviewInstance::MontagePreview_SetPlaying(bool bIsPlaying) } else if (Proxy.IsPlaying()) { - UAnimMontage* Montage = Cast(Proxy.GetCurrentAsset()); + UAnimMontage* Montage = Cast(CurrentAsset); if (Montage) { switch (MontagePreviewType) @@ -546,7 +546,7 @@ void UAnimPreviewInstance::MontagePreview_SetReverse(bool bInReverse) void UAnimPreviewInstance::MontagePreview_Restart() { FAnimPreviewInstanceProxy& Proxy = GetProxyOnGameThread(); - if (UAnimMontage* Montage = Cast(Proxy.GetCurrentAsset())) + if (UAnimMontage* Montage = Cast(CurrentAsset)) { switch (MontagePreviewType) { @@ -565,7 +565,7 @@ void UAnimPreviewInstance::MontagePreview_StepForward() { FAnimPreviewInstanceProxy& Proxy = GetProxyOnGameThread(); - if (UAnimMontage* Montage = Cast(Proxy.GetCurrentAsset())) + if (UAnimMontage* Montage = Cast(CurrentAsset)) { bool bWasPlaying = IsPlayingMontage() && (Proxy.IsLooping() || Proxy.IsPlaying()); // we need to handle non-looped case separately, even if paused during playthrough MontagePreview_SetReverse(false); @@ -615,10 +615,9 @@ void UAnimPreviewInstance::MontagePreview_StepForward() void UAnimPreviewInstance::MontagePreview_StepBackward() { - FAnimPreviewInstanceProxy& Proxy = GetProxyOnGameThread(); - - if (UAnimMontage* Montage = Cast(Proxy.GetCurrentAsset())) + if (UAnimMontage* Montage = Cast(CurrentAsset)) { + FAnimPreviewInstanceProxy& Proxy = GetProxyOnGameThread(); bool bWasPlaying = IsPlayingMontage() && (Proxy.IsLooping() || Proxy.IsPlaying()); // we need to handle non-looped case separately, even if paused during playthrough MontagePreview_SetReverse(true); if (! bWasPlaying) @@ -677,9 +676,10 @@ float UAnimPreviewInstance::MontagePreview_CalculateStepLength() void UAnimPreviewInstance::MontagePreview_JumpToStart() { - FAnimPreviewInstanceProxy& Proxy = GetProxyOnGameThread(); - if (UAnimMontage* Montage = Cast(Proxy.GetCurrentAsset())) + if (UAnimMontage* Montage = Cast(CurrentAsset)) { + FAnimPreviewInstanceProxy& Proxy = GetProxyOnGameThread(); + int32 SectionIdx = 0; if (MontagePreviewType == EMPT_Normal) { @@ -708,9 +708,10 @@ void UAnimPreviewInstance::MontagePreview_JumpToStart() void UAnimPreviewInstance::MontagePreview_JumpToEnd() { - FAnimPreviewInstanceProxy& Proxy = GetProxyOnGameThread(); - if (UAnimMontage* Montage = Cast(Proxy.GetCurrentAsset())) + if (UAnimMontage* Montage = Cast(CurrentAsset)) { + FAnimPreviewInstanceProxy& Proxy = GetProxyOnGameThread(); + int32 SectionIdx = 0; if (MontagePreviewType == EMPT_Normal) { @@ -739,10 +740,10 @@ void UAnimPreviewInstance::MontagePreview_JumpToEnd() void UAnimPreviewInstance::MontagePreview_JumpToPreviewStart() { - FAnimPreviewInstanceProxy& Proxy = GetProxyOnGameThread(); - - if (UAnimMontage* Montage = Cast(Proxy.GetCurrentAsset())) + if (UAnimMontage* Montage = Cast(CurrentAsset)) { + FAnimPreviewInstanceProxy& Proxy = GetProxyOnGameThread(); + int32 SectionIdx = 0; if (MontagePreviewType == EMPT_Normal) { @@ -764,11 +765,11 @@ void UAnimPreviewInstance::MontagePreview_JumpToPreviewStart() void UAnimPreviewInstance::MontagePreview_JumpToPosition(float NewPosition) { - FAnimPreviewInstanceProxy& Proxy = GetProxyOnGameThread(); - SetPosition(NewPosition, false); - if (UAnimMontage* Montage = Cast(Proxy.GetCurrentAsset())) + if (UAnimMontage* Montage = Cast(CurrentAsset)) { + FAnimPreviewInstanceProxy& Proxy = GetProxyOnGameThread(); + // this section will be first int32 NewMontagePreviewStartSectionIdx = MontagePreview_FindFirstSectionAsInMontage(Montage->GetSectionIndexFromPosition(NewPosition)); if (MontagePreviewStartSectionIdx != NewMontagePreviewStartSectionIdx && @@ -791,10 +792,10 @@ void UAnimPreviewInstance::MontagePreview_RemoveBlendOut() void UAnimPreviewInstance::MontagePreview_PreviewNormal(int32 FromSectionIdx) { - FAnimPreviewInstanceProxy& Proxy = GetProxyOnGameThread(); - - if (UAnimMontage* Montage = Cast(Proxy.GetCurrentAsset())) + if (UAnimMontage* Montage = Cast(CurrentAsset)) { + FAnimPreviewInstanceProxy& Proxy = GetProxyOnGameThread(); + int32 PreviewFromSection = FromSectionIdx; if (FromSectionIdx != INDEX_NONE) { @@ -819,11 +820,11 @@ void UAnimPreviewInstance::MontagePreview_PreviewNormal(int32 FromSectionIdx) void UAnimPreviewInstance::MontagePreview_PreviewAllSections() { - FAnimPreviewInstanceProxy& Proxy = GetProxyOnGameThread(); - - UAnimMontage* Montage = Cast(Proxy.GetCurrentAsset()); + UAnimMontage* Montage = Cast(CurrentAsset); if (Montage && Montage->SequenceLength > 0.f) { + FAnimPreviewInstanceProxy& Proxy = GetProxyOnGameThread(); + MontagePreviewType = EMPT_AllSections; // since this is preview, we would like not to blend in // just hard stop here @@ -838,10 +839,10 @@ void UAnimPreviewInstance::MontagePreview_PreviewAllSections() void UAnimPreviewInstance::MontagePreview_SetLoopNormal(bool bIsLooping, int32 PreferSectionIdx) { - FAnimPreviewInstanceProxy& Proxy = GetProxyOnGameThread(); - - if (UAnimMontage* Montage = Cast(Proxy.GetCurrentAsset())) + if (UAnimMontage* Montage = Cast(CurrentAsset)) { + FAnimPreviewInstanceProxy& Proxy = GetProxyOnGameThread(); + MontagePreview_ResetSectionsOrder(); if (PreferSectionIdx == INDEX_NONE) @@ -904,10 +905,10 @@ void UAnimPreviewInstance::MontagePreview_SetLoopNormal(bool bIsLooping, int32 P void UAnimPreviewInstance::MontagePreview_SetLoopAllSetupSections(bool bIsLooping) { - FAnimPreviewInstanceProxy& Proxy = GetProxyOnGameThread(); - - if (UAnimMontage* Montage = Cast(Proxy.GetCurrentAsset())) + if (UAnimMontage* Montage = Cast(CurrentAsset)) { + FAnimPreviewInstanceProxy& Proxy = GetProxyOnGameThread(); + MontagePreview_ResetSectionsOrder(); int32 TotalSection = Montage->CompositeSections.Num(); @@ -961,10 +962,10 @@ void UAnimPreviewInstance::MontagePreview_SetLoopAllSetupSections(bool bIsLoopin void UAnimPreviewInstance::MontagePreview_SetLoopAllSections(bool bIsLooping) { - FAnimPreviewInstanceProxy& Proxy = GetProxyOnGameThread(); - - if (UAnimMontage* Montage = Cast(Proxy.GetCurrentAsset())) + if (UAnimMontage* Montage = Cast(CurrentAsset)) { + FAnimPreviewInstanceProxy& Proxy = GetProxyOnGameThread(); + int32 TotalSection = Montage->CompositeSections.Num(); if (TotalSection > 0) { @@ -989,8 +990,7 @@ void UAnimPreviewInstance::MontagePreview_SetLoopAllSections(bool bIsLooping) void UAnimPreviewInstance::MontagePreview_ResetSectionsOrder() { - FAnimPreviewInstanceProxy& Proxy = GetProxyOnGameThread(); - if (UAnimMontage* Montage = Cast(Proxy.GetCurrentAsset())) + if (UAnimMontage* Montage = Cast(CurrentAsset)) { int32 TotalSection = Montage->CompositeSections.Num(); // restore to default @@ -1003,10 +1003,9 @@ void UAnimPreviewInstance::MontagePreview_ResetSectionsOrder() int32 UAnimPreviewInstance::MontagePreview_FindFirstSectionAsInMontage(int32 ForSectionIdx) { - FAnimPreviewInstanceProxy& Proxy = GetProxyOnGameThread(); int32 ResultIdx = ForSectionIdx; // Montage does not have looping set up, so it should be valid and it gets - if (UAnimMontage* Montage = Cast(Proxy.GetCurrentAsset())) + if (UAnimMontage* Montage = Cast(CurrentAsset)) { TArray AlreadyVisited; AlreadyVisited.AddZeroed(Montage->CompositeSections.Num()); @@ -1047,9 +1046,8 @@ int32 UAnimPreviewInstance::MontagePreview_FindFirstSectionAsInMontage(int32 For int32 UAnimPreviewInstance::MontagePreview_FindLastSection(int32 StartSectionIdx) { - FAnimPreviewInstanceProxy& Proxy = GetProxyOnGameThread(); int32 ResultIdx = StartSectionIdx; - if (UAnimMontage* Montage = Cast(Proxy.GetCurrentAsset())) + if (UAnimMontage* Montage = Cast(CurrentAsset)) { if (FAnimMontageInstance* CurMontageInstance = GetActiveMontageInstance()) { diff --git a/Engine/Source/Editor/AnimGraph/Private/AnimStateNodeBase.cpp b/Engine/Source/Editor/AnimGraph/Private/AnimStateNodeBase.cpp index 615f269fb731..5242973d4c63 100644 --- a/Engine/Source/Editor/AnimGraph/Private/AnimStateNodeBase.cpp +++ b/Engine/Source/Editor/AnimGraph/Private/AnimStateNodeBase.cpp @@ -10,6 +10,7 @@ #include "EdGraphUtilities.h" #include "Kismet2/Kismet2NameValidators.h" #include "AnimStateNodeBase.h" +#include "FrameworkObjectVersion.h" ///////////////////////////////////////////////////// // FAnimStateNodeNameValidator @@ -93,6 +94,37 @@ FString UAnimStateNodeBase::GetDocumentationLink() const return TEXT("Shared/GraphNodes/AnimationStateMachine"); } +void UAnimStateNodeBase::Serialize(FArchive& Ar) +{ + Super::Serialize(Ar); + Ar.UsingCustomVersion(FFrameworkObjectVersion::GUID); +} + +void UAnimStateNodeBase::PostLoad() +{ + Super::PostLoad(); + + const int32 CustomVersion = GetLinkerCustomVersion(FFrameworkObjectVersion::GUID); + + if(CustomVersion < FFrameworkObjectVersion::FixNonTransactionalPins) + { + int32 BrokenPinCount = 0; + for(UEdGraphPin* Pin : Pins) + { + if(!Pin->HasAnyFlags(RF_Transactional)) + { + ++BrokenPinCount; + Pin->SetFlags(Pin->GetFlags() | RF_Transactional); + } + } + + if(BrokenPinCount > 0) + { + UE_LOG(LogAnimation, Log, TEXT("Fixed %d non-transactional pins in %s"), BrokenPinCount, *GetName()); + } + } +} + UAnimBlueprint* UAnimStateNodeBase::GetAnimBlueprint() const { UBlueprint* Blueprint = FBlueprintEditorUtils::FindBlueprintForNode(this); diff --git a/Engine/Source/Editor/BlueprintGraph/Classes/K2Node_GetClassDefaults.h b/Engine/Source/Editor/BlueprintGraph/Classes/K2Node_GetClassDefaults.h index 497c6c8734d2..af532015db68 100644 --- a/Engine/Source/Editor/BlueprintGraph/Classes/K2Node_GetClassDefaults.h +++ b/Engine/Source/Editor/BlueprintGraph/Classes/K2Node_GetClassDefaults.h @@ -35,11 +35,17 @@ class UK2Node_GetClassDefaults : public UK2Node public: /** Finds and returns the class input pin from the current set of pins. */ - UEdGraphPin* FindClassPin() const + BLUEPRINTGRAPH_API UEdGraphPin* FindClassPin() const { return FindClassPin(Pins); } + /** Retrieves the current input class type. */ + BLUEPRINTGRAPH_API UClass* GetInputClass() const + { + return GetInputClass(FindClassPin()); + } + protected: /** * Finds and returns the class input pin. @@ -49,11 +55,11 @@ protected: UEdGraphPin* FindClassPin(const TArray& FromPins) const; /** - * Determines the input class type from the given pin. - * - * @param FromPin Input class pin. If not set (default), then it will fall back to using FindClassPin(). - */ - UClass* GetInputClass(const UEdGraphPin* FromPin = nullptr) const; + * Determines the input class type from the given pin. + * + * @param FromPin Input class pin. + */ + UClass* GetInputClass(const UEdGraphPin* FromPin) const; /** * Creates the full set of output pins (properties) from the given input class. @@ -69,6 +75,12 @@ private: /** Class pin name */ static FString ClassPinName; + /** Blueprint.OnChanged delegate handle */ + FDelegateHandle OnBlueprintChangedDelegate; + + /** Blueprint.OnCompiled delegate handle */ + FDelegateHandle OnBlueprintCompiledDelegate; + /** Output pin visibility control */ UPROPERTY(EditAnywhere, Category=PinOptions, EditFixedSize) TArray ShowPinForProperties; diff --git a/Engine/Source/Editor/BlueprintGraph/Private/DelegateNodeHandlers.cpp b/Engine/Source/Editor/BlueprintGraph/Private/DelegateNodeHandlers.cpp index df83143e1479..74e4369283d9 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/DelegateNodeHandlers.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/DelegateNodeHandlers.cpp @@ -194,14 +194,14 @@ void FKCHandler_CreateDelegate::RegisterNets(FKismetFunctionContext& Context, UE const FName DelegateFunctionName = DelegateNode->GetFunctionName(); if(DelegateFunctionName == NAME_None) { - CompilerContext.MessageLog.Error(*LOCTEXT("NoDelegateFunctionName", "No delegate function name @@").ToString(), DelegateNode); + CompilerContext.MessageLog.Error(*LOCTEXT("NoDelegateFunctionName", "@@ : missing a function/event name.").ToString(), DelegateNode); return; } if(!DelegateNode->GetDelegateSignature()) { const FString ErrorStr = FString::Printf( - *LOCTEXT("NoDelegateFunction", "No delegate function '%' @@").ToString(), + *LOCTEXT("NoDelegateFunction", "@@ : unable to determine expected signature - is the delegate pin connected?").ToString(), *DelegateFunctionName.ToString()); CompilerContext.MessageLog.Error(*ErrorStr, DelegateNode); return; diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_CallFunction.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_CallFunction.cpp index c943a907bad3..216e4135baf7 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_CallFunction.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_CallFunction.cpp @@ -716,8 +716,12 @@ void UK2Node_CallFunction::CreateExecPinsForFunctionCall(const UFunction* Functi int32 NumExecs = (EnumProp->Enum->NumEnums() - 1); for(int32 ExecIdx=0; ExecIdxEnum->GetEnumName(ExecIdx); - CreatePin(Direction, K2Schema->PC_Exec, TEXT(""), NULL, false, false, ExecName); + bool const bShouldBeHidden = EnumProp->Enum->HasMetaData(TEXT("Hidden"), ExecIdx) || EnumProp->Enum->HasMetaData(TEXT("Spacer"), ExecIdx); + if (!bShouldBeHidden) + { + FString ExecName = EnumProp->Enum->GetEnumName(ExecIdx); + CreatePin(Direction, K2Schema->PC_Exec, TEXT(""), NULL, false, false, ExecName); + } } if (bIsFunctionInput) diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_ConstructObjectFromClass.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_ConstructObjectFromClass.cpp index 0af5f67bcef3..3b4feaa494d6 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_ConstructObjectFromClass.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_ConstructObjectFromClass.cpp @@ -68,7 +68,7 @@ void UK2Node_ConstructObjectFromClass::AllocateDefaultPins() UEdGraphPin* UK2Node_ConstructObjectFromClass::GetOuterPin() const { - UEdGraphPin* Pin = FindPinChecked(FK2Node_ConstructObjectFromClassHelper::OuterPinName); + UEdGraphPin* Pin = FindPin(FK2Node_ConstructObjectFromClassHelper::OuterPinName); ensure(nullptr == Pin || Pin->Direction == EGPD_Input); return Pin; } @@ -232,11 +232,20 @@ void UK2Node_ConstructObjectFromClass::PinConnectionListChanged(UEdGraphPin* Pin void UK2Node_ConstructObjectFromClass::GetPinHoverText(const UEdGraphPin& Pin, FString& HoverTextOut) const { - SetPinToolTip(*GetClassPin(), LOCTEXT("ClassPinDescription", "The object class you want to construct")); - SetPinToolTip(*GetResultPin(), LOCTEXT("ResultPinDescription", "The constructed object")); - if (UseOuter()) + UEdGraphPin* ClassPin = GetClassPin(); + if (ClassPin) { - SetPinToolTip(*GetOuterPin(), LOCTEXT("OuterPinDescription", "Owner of the constructed object")); + SetPinToolTip(*ClassPin, LOCTEXT("ClassPinDescription", "The object class you want to construct")); + } + UEdGraphPin* ResultPin = GetResultPin(); + if (ResultPin) + { + SetPinToolTip(*ResultPin, LOCTEXT("ResultPinDescription", "The constructed object")); + } + UEdGraphPin* OuterPin = UseOuter() ? GetOuterPin() : nullptr; + if (OuterPin) + { + SetPinToolTip(*OuterPin, LOCTEXT("OuterPinDescription", "Owner of the constructed object")); } return Super::GetPinHoverText(Pin, HoverTextOut); diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_CreateDelegate.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_CreateDelegate.cpp index 9455376a4440..c374487653f6 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_CreateDelegate.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_CreateDelegate.cpp @@ -8,7 +8,6 @@ struct FK2Node_CreateDelegate_Helper { - static FString ObjectInputName; static FString DelegateOutputName; }; FString FK2Node_CreateDelegate_Helper::DelegateOutputName(TEXT("OutputDelegate")); @@ -37,12 +36,12 @@ void UK2Node_CreateDelegate::AllocateDefaultPins() bool UK2Node_CreateDelegate::IsValid(FString* OutMsg, bool bDontUseSkeletalClassForSelf) const { - - if (GetFunctionName() == NAME_None) + FName FunctionName = GetFunctionName(); + if (FunctionName == NAME_None) { if (OutMsg) { - *OutMsg = NSLOCTEXT("K2Node", "No_function_name", "No function name.").ToString(); + *OutMsg = NSLOCTEXT("K2Node", "No_function_name", "No function/event specified.").ToString(); } return false; } @@ -52,7 +51,7 @@ bool UK2Node_CreateDelegate::IsValid(FString* OutMsg, bool bDontUseSkeletalClass { if (OutMsg) { - *OutMsg = NSLOCTEXT("K2Node", "No_delegate_out_pin", "No delegate out pin.").ToString(); + *OutMsg = NSLOCTEXT("K2Node", "No_delegate_out_pin", "Malformed node - there's no delegate output pin.").ToString(); } return false; } @@ -62,7 +61,7 @@ bool UK2Node_CreateDelegate::IsValid(FString* OutMsg, bool bDontUseSkeletalClass { if (OutMsg) { - *OutMsg = NSLOCTEXT("K2Node", "Signature_not_found", "Signature not found.").ToString(); + *OutMsg = NSLOCTEXT("K2Node", "Signature_not_found", "Unable to determine expected signature - is the delegate pin connected?").ToString(); } return false; } @@ -76,7 +75,17 @@ bool UK2Node_CreateDelegate::IsValid(FString* OutMsg, bool bDontUseSkeletalClass { if (OutMsg) { - *OutMsg = NSLOCTEXT("K2Node", "No_delegate_out_pin", "No delegate out pin.").ToString(); + if (const UK2Node_BaseMCDelegate* DelegateNode = Cast(OtherPin->GetOwningNode())) + { + const FString DelegateName = DelegateNode->GetPropertyName().ToString(); + + *OutMsg = FString::Printf(*NSLOCTEXT("K2Node", "Bad_delegate_connection_named", "A connected delegate (%s) has an incompatible signature - has that delegate changed?").ToString(), + *DelegateName); + } + else + { + *OutMsg = NSLOCTEXT("K2Node", "Bad_delegate_connection", "A connected delegate's signature is incompatible - has that delegate changed?").ToString(); + } } return false; } @@ -87,7 +96,14 @@ bool UK2Node_CreateDelegate::IsValid(FString* OutMsg, bool bDontUseSkeletalClass { if (OutMsg) { - *OutMsg = NSLOCTEXT("K2Node", "Class_not_found", "Class not found.").ToString(); + FString SelfPinName = UEdGraphSchema_K2::PN_Self; + if (UEdGraphPin* SelfPin = GetObjectInPin()) + { + SelfPinName = SelfPin->PinFriendlyName.IsEmpty() ? SelfPin->PinFriendlyName.ToString() : SelfPin->PinName; + } + + *OutMsg = FString::Printf(*NSLOCTEXT("K2Node", "Class_not_found", "Unable to determine context for the selected function/event: '%s' - make sure the target '%s' pin is properly set up.").ToString(), + *FunctionName.ToString(), *SelfPinName); } return false; } @@ -99,7 +115,9 @@ bool UK2Node_CreateDelegate::IsValid(FString* OutMsg, bool bDontUseSkeletalClass { if (OutMsg) { - *OutMsg = NSLOCTEXT("K2Node", "Function_not_found", "Function not found.").ToString(); + *OutMsg = FString::Printf(*NSLOCTEXT("K2Node", "Function_not_found", "Unable to find the selected function/event: '%s' - has it been deleted?").ToString(), + *FunctionName.ToString()); + } return false; } @@ -107,7 +125,8 @@ bool UK2Node_CreateDelegate::IsValid(FString* OutMsg, bool bDontUseSkeletalClass { if (OutMsg) { - *OutMsg = NSLOCTEXT("K2Node", "Function_not_compatible", "Function not compatible.").ToString(); + *OutMsg = FString::Printf(*NSLOCTEXT("K2Node", "Function_not_compatible", "The function/event '%s' does not match the necessary signature - has the delegate or function/event changed?").ToString(), + *FunctionName.ToString()); } return false; } @@ -115,7 +134,8 @@ bool UK2Node_CreateDelegate::IsValid(FString* OutMsg, bool bDontUseSkeletalClass { if (OutMsg) { - *OutMsg = NSLOCTEXT("K2Node", "Function_cannot_be_used_in_delegate", "Function cannot be used in delegate.").ToString(); + *OutMsg = FString::Printf(*NSLOCTEXT("K2Node", "Function_cannot_be_used_in_delegate", "The selected function/event is not bindable - is the function/event pure or latent?").ToString(), + *FunctionName.ToString()); } return false; } @@ -130,7 +150,8 @@ bool UK2Node_CreateDelegate::IsValid(FString* OutMsg, bool bDontUseSkeletalClass { if(OutMsg) { - *OutMsg = NSLOCTEXT("K2Node", "WrongDelegateAuthorityOnly", "No AuthorityOnly flag").ToString(); + *OutMsg = FString::Printf(*NSLOCTEXT("K2Node", "WrongDelegateAuthorityOnly", "The selected function/event ('%s') is not compatible with this delegate (the delegate is server-only) - try marking the function/event AuthorityOnly.").ToString(), + *FunctionName.ToString()); } return false; } @@ -145,7 +166,7 @@ void UK2Node_CreateDelegate::ValidationAfterFunctionsAreCreated(class FCompilerR FString Msg; if(!IsValid(&Msg, bFullCompile)) { - MessageLog.Error(*FString::Printf( TEXT("%s %s @@"), *NSLOCTEXT("K2Node", "WrongDelegate", "Event signature error: ").ToString(), *Msg), this); + MessageLog.Error(*FString::Printf( TEXT("@@ %s %s"), *NSLOCTEXT("K2Node", "WrongDelegate", "Signature Error:").ToString(), *Msg), this); } } @@ -172,7 +193,16 @@ void UK2Node_CreateDelegate::HandleAnyChangeWithoutNotifying() if(!IsValid()) { - SelectedFunctionName = NAME_None; + // do not clear the name, so we can keep it around as a hint/guide for + // users (so they can better determine what went wrong) + if (const UEdGraphPin* DelegatePin = GetDelegateOutPin()) + { + if (DelegatePin->LinkedTo.Num() == 0) + { + // ok to clear if they've disconnected the delegate pin + SelectedFunctionName = NAME_None; + } + } SelectedFunctionGuid.Invalidate(); } } @@ -340,8 +370,7 @@ UEdGraphPin* UK2Node_CreateDelegate::GetDelegateOutPin() const UEdGraphPin* UK2Node_CreateDelegate::GetObjectInPin() const { - const UEdGraphSchema_K2* K2Schema = GetDefault(); - return FindPinChecked(K2Schema->PN_Self); + return FindPin(UEdGraphSchema_K2::PN_Self); } FText UK2Node_CreateDelegate::GetNodeTitle(ENodeTitleType::Type TitleType) const diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_GetClassDefaults.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_GetClassDefaults.cpp index 57e5d229b770..fb24a1d892a7 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_GetClassDefaults.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_GetClassDefaults.cpp @@ -349,29 +349,32 @@ UClass* UK2Node_GetClassDefaults::GetInputClass(const UEdGraphPin* FromPin) cons { UClass* InputClass = nullptr; - const UEdGraphPin* ClassPin = FromPin; - if(ClassPin == nullptr) + if (FromPin != nullptr) { - ClassPin = FindClassPin(); - } - - if(ClassPin != nullptr) - { - check(ClassPin->Direction == EGPD_Input); + check(FromPin->Direction == EGPD_Input); - if(ClassPin->DefaultObject != nullptr && ClassPin->LinkedTo.Num() == 0) + if (FromPin->DefaultObject != nullptr && FromPin->LinkedTo.Num() == 0) { - InputClass = CastChecked(ClassPin->DefaultObject); + InputClass = CastChecked(FromPin->DefaultObject); } - else if(ClassPin->LinkedTo.Num() > 0) + else if (FromPin->LinkedTo.Num() > 0) { - if(UEdGraphPin* LinkedPin = ClassPin->LinkedTo[0]) + if (UEdGraphPin* LinkedPin = FromPin->LinkedTo[0]) { InputClass = Cast(LinkedPin->PinType.PinSubCategoryObject.Get()); } } } + // Switch Blueprint Class types to use the generated skeleton class. + if (InputClass) + { + if (UBlueprint* Blueprint = Cast(InputClass->ClassGeneratedBy)) + { + InputClass = Blueprint->SkeletonGeneratedClass; + } + } + return InputClass; } @@ -401,6 +404,25 @@ void UK2Node_GetClassDefaults::CreateOutputPins(UClass* InClass) { AdvancedPinDisplay = ENodeAdvancedPins::NoPins; } + + // Unbind OnChanged() delegate from a previous Blueprint, if valid. + if (OnBlueprintChangedDelegate.IsValid()) + { + OnBlueprintChangedDelegate.Reset(); + } + + // Unbind OnCompiled() delegate from a previous Blueprint, if valid. + if (OnBlueprintCompiledDelegate.IsValid()) + { + OnBlueprintCompiledDelegate.Reset(); + } + + // If the class was generated for a Blueprint, bind delegates to handle any OnChanged() & OnCompiled() events. + if (UBlueprint* Blueprint = Cast(InClass->ClassGeneratedBy)) + { + OnBlueprintChangedDelegate = Blueprint->OnChanged().AddLambda([this](UBlueprint* /* InBlueprint */) { ReconstructNode(); }); + OnBlueprintCompiledDelegate = Blueprint->OnCompiled().AddLambda([this](UBlueprint* /* InBlueprint */) { ReconstructNode(); }); + } } void UK2Node_GetClassDefaults::OnClassPinChanged() diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_MakeStruct.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_MakeStruct.cpp index fa336f83a39b..fdfa6beae4f4 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_MakeStruct.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_MakeStruct.cpp @@ -361,67 +361,70 @@ void UK2Node_MakeStruct::Serialize(FArchive& Ar) { // Check if this node actually requires warning the user that functionality has changed. bMadeAfterOverridePinRemoval = true; - FOptionalPinManager PinManager; - - // Preload all pins so we can examine their values - for (UEdGraphPin* Pin : Pins) + if (StructType != nullptr) { - Ar.Preload(Pin); - } + FOptionalPinManager PinManager; - // Have to check if this node is even in danger. - for (FOptionalPinFromProperty& PropertyEntry : ShowPinForProperties) - { - UProperty* Property = StructType->FindPropertyByName(PropertyEntry.PropertyName); - bool bNegate = false; - if (UProperty* OverrideProperty = PropertyCustomizationHelpers::GetEditConditionProperty(Property, bNegate)) + // Preload all pins so we can examine their values + for (UEdGraphPin* Pin : Pins) { - bool bHadOverridePropertySeparation = false; - for (FOptionalPinFromProperty& OverridePropertyEntry : ShowPinForProperties) + Ar.Preload(Pin); + } + + // Have to check if this node is even in danger. + for (FOptionalPinFromProperty& PropertyEntry : ShowPinForProperties) + { + UProperty* Property = StructType->FindPropertyByName(PropertyEntry.PropertyName); + bool bNegate = false; + if (UProperty* OverrideProperty = PropertyCustomizationHelpers::GetEditConditionProperty(Property, bNegate)) { - if (OverridePropertyEntry.PropertyName == OverrideProperty->GetFName()) + bool bHadOverridePropertySeparation = false; + for (FOptionalPinFromProperty& OverridePropertyEntry : ShowPinForProperties) { - bHadOverridePropertySeparation = true; - break; + if (OverridePropertyEntry.PropertyName == OverrideProperty->GetFName()) + { + bHadOverridePropertySeparation = true; + break; + } } - } - bMadeAfterOverridePinRemoval = false; - UEdGraphPin* Pin = FindPin(Property->GetName()); + bMadeAfterOverridePinRemoval = false; + UEdGraphPin* Pin = FindPin(Property->GetName()); - if (bHadOverridePropertySeparation) - { - UEdGraphPin* OverridePin = FindPin(OverrideProperty->GetName()); - const UEdGraphSchema_K2* Schema = GetDefault(); - if (OverridePin) + if (bHadOverridePropertySeparation) { - // Override pins are always booleans - check(OverridePin->PinType.PinCategory == Schema->PC_Boolean); - // If the old override pin's default value was true, then the override should be marked as enabled - PropertyEntry.bIsOverrideEnabled = OverridePin->DefaultValue.ToBool(); - // It had an override pin, so conceptually the override pin is visible - PropertyEntry.bIsOverridePinVisible = true; - // Because there was an override pin visible for this property, this property will be forced to have a pin - PropertyEntry.bShowPin = true; + UEdGraphPin* OverridePin = FindPin(OverrideProperty->GetName()); + const UEdGraphSchema_K2* Schema = GetDefault(); + if (OverridePin) + { + // Override pins are always booleans + check(OverridePin->PinType.PinCategory == Schema->PC_Boolean); + // If the old override pin's default value was true, then the override should be marked as enabled + PropertyEntry.bIsOverrideEnabled = OverridePin->DefaultValue.ToBool(); + // It had an override pin, so conceptually the override pin is visible + PropertyEntry.bIsOverridePinVisible = true; + // Because there was an override pin visible for this property, this property will be forced to have a pin + PropertyEntry.bShowPin = true; + } + else + { + // No override pin, ensure all override bools are false + PropertyEntry.bIsOverrideEnabled = false; + PropertyEntry.bIsOverridePinVisible = false; + } } else { - // No override pin, ensure all override bools are false - PropertyEntry.bIsOverrideEnabled = false; - PropertyEntry.bIsOverridePinVisible = false; + if (Pin) + { + PropertyEntry.bIsOverrideEnabled = true; + PropertyEntry.bIsOverridePinVisible = true; + } } - } - else - { - if (Pin) - { - PropertyEntry.bIsOverrideEnabled = true; - PropertyEntry.bIsOverridePinVisible = true; - } - } - // If the pin for this property, which sets the property's value, does not exist then the user was not trying to set the value - PropertyEntry.bIsSetValuePinVisible = Pin != nullptr; + // If the pin for this property, which sets the property's value, does not exist then the user was not trying to set the value + PropertyEntry.bIsSetValuePinVisible = Pin != nullptr; + } } } } diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_SpawnActorFromClass.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_SpawnActorFromClass.cpp index aa7124b08678..30dc612b9e05 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_SpawnActorFromClass.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_SpawnActorFromClass.cpp @@ -375,16 +375,26 @@ void UK2Node_SpawnActorFromClass::GetPinHoverText(const UEdGraphPin& Pin, FStrin { const UEdGraphSchema_K2* K2Schema = GetDefault(); - UEdGraphPin* ClassPin = GetClassPin(); - K2Schema->ConstructBasicPinTooltip(*ClassPin, LOCTEXT("ClassPinDescription", "The Actor class you want to spawn"), ClassPin->PinToolTip); - UEdGraphPin* TransformPin = GetSpawnTransformPin(); - K2Schema->ConstructBasicPinTooltip(*TransformPin, LOCTEXT("TransformPinDescription", "The transform to spawn the Actor with"), TransformPin->PinToolTip); - UEdGraphPin* CollisionHandlingOverridePin = GetCollisionHandlingOverridePin(); - K2Schema->ConstructBasicPinTooltip(*CollisionHandlingOverridePin, LOCTEXT("CollisionHandlingOverridePinDescription", "Specifies how to handle collisions at the spawn point. If undefined, uses actor class settings."), CollisionHandlingOverridePin->PinToolTip); - UEdGraphPin* OwnerPin = GetOwnerPin(); - K2Schema->ConstructBasicPinTooltip(*OwnerPin, LOCTEXT("OwnerPinDescription", "Can be left empty; primarily used for replication (bNetUseOwnerRelevancy and bOnlyRelevantToOwner), or visibility (PrimitiveComponent's bOwnerNoSee/bOnlyOwnerSee)"), OwnerPin->PinToolTip); - UEdGraphPin* ResultPin = GetResultPin(); - K2Schema->ConstructBasicPinTooltip(*ResultPin, LOCTEXT("ResultPinDescription", "The spawned Actor"), ResultPin->PinToolTip); + if (UEdGraphPin* ClassPin = GetClassPin()) + { + K2Schema->ConstructBasicPinTooltip(*ClassPin, LOCTEXT("ClassPinDescription", "The Actor class you want to spawn"), ClassPin->PinToolTip); + } + if (UEdGraphPin* TransformPin = GetSpawnTransformPin()) + { + K2Schema->ConstructBasicPinTooltip(*TransformPin, LOCTEXT("TransformPinDescription", "The transform to spawn the Actor with"), TransformPin->PinToolTip); + } + if (UEdGraphPin* CollisionHandlingOverridePin = GetCollisionHandlingOverridePin()) + { + K2Schema->ConstructBasicPinTooltip(*CollisionHandlingOverridePin, LOCTEXT("CollisionHandlingOverridePinDescription", "Specifies how to handle collisions at the spawn point. If undefined, uses actor class settings."), CollisionHandlingOverridePin->PinToolTip); + } + if (UEdGraphPin* OwnerPin = GetOwnerPin()) + { + K2Schema->ConstructBasicPinTooltip(*OwnerPin, LOCTEXT("OwnerPinDescription", "Can be left empty; primarily used for replication (bNetUseOwnerRelevancy and bOnlyRelevantToOwner), or visibility (PrimitiveComponent's bOwnerNoSee/bOnlyOwnerSee)"), OwnerPin->PinToolTip); + } + if (UEdGraphPin* ResultPin = GetResultPin()) + { + K2Schema->ConstructBasicPinTooltip(*ResultPin, LOCTEXT("ResultPinDescription", "The spawned Actor"), ResultPin->PinToolTip); + } return Super::GetPinHoverText(Pin, HoverTextOut); } diff --git a/Engine/Source/Editor/BlueprintGraph/Public/BlueprintGraphDefinitions.h b/Engine/Source/Editor/BlueprintGraph/Public/BlueprintGraphDefinitions.h index 1d991705e732..32d18dd6cbb7 100644 --- a/Engine/Source/Editor/BlueprintGraph/Public/BlueprintGraphDefinitions.h +++ b/Engine/Source/Editor/BlueprintGraph/Public/BlueprintGraphDefinitions.h @@ -34,6 +34,7 @@ #include "K2Node_FormatText.h" #include "K2Node_FunctionEntry.h" #include "K2Node_FunctionResult.h" +#include "K2Node_GetClassDefaults.h" #include "K2Node_GetDataTableRow.h" #include "K2Node_GetArrayItem.h" #include "K2Node_IfThenElse.h" diff --git a/Engine/Source/Editor/Blutility/Private/AssetTypeActions_EditorUtilityBlueprint.h b/Engine/Source/Editor/Blutility/Private/AssetTypeActions_EditorUtilityBlueprint.h index 83021d5803a9..360ad1fe60cb 100644 --- a/Engine/Source/Editor/Blutility/Private/AssetTypeActions_EditorUtilityBlueprint.h +++ b/Engine/Source/Editor/Blutility/Private/AssetTypeActions_EditorUtilityBlueprint.h @@ -15,6 +15,7 @@ public: virtual void GetActions(const TArray& InObjects, FMenuBuilder& MenuBuilder) override; virtual void OpenAssetEditor(const TArray& InObjects, TSharedPtr EditWithinLevelEditor = TSharedPtr()) override; virtual uint32 GetCategories() override; + virtual bool CanLocalize() const override { return false; } // End of IAssetTypeActions interface protected: diff --git a/Engine/Source/Editor/ClassViewer/Private/SClassViewer.cpp b/Engine/Source/Editor/ClassViewer/Private/SClassViewer.cpp index 4020316dce8d..628619d1e63d 100644 --- a/Engine/Source/Editor/ClassViewer/Private/SClassViewer.cpp +++ b/Engine/Source/Editor/ClassViewer/Private/SClassViewer.cpp @@ -33,6 +33,7 @@ #include "SourceCodeNavigation.h" #include "HotReloadInterface.h" #include "SSearchBox.h" +#include "TextFilterExpressionEvaluator.h" #include "SListViewSelectorDropdownMenu.h" #include "Engine/BlueprintGeneratedClass.h" @@ -535,27 +536,36 @@ namespace ClassViewer } /** Checks if the TestString passes the filter. - * @param InTestString The string to test against the filter. - * @param InFilterSearchTerms A list of terms to filter with. + * @param InTestString The string to test against the filter. + * @param InTextFilter Compiled text filter to apply. * * @return true if it passes the filter. */ - static bool PassesFilter( const FString& InTestString, const TArray& InFilterSearchTerms ) + static bool PassesFilter( const FString& InTestString, const FTextFilterExpressionEvaluator& InTextFilter ) { - bool bPassesFilter = false; - - bPassesFilter = !InFilterSearchTerms.Num(); - - for( auto CurSearchTermIndex = 0; !bPassesFilter && CurSearchTermIndex < InFilterSearchTerms.Num(); ++CurSearchTermIndex ) + class FClassFilterContext : public ITextFilterExpressionContext { - if(InTestString.Contains(InFilterSearchTerms[CurSearchTermIndex])) + public: + explicit FClassFilterContext(const FString& InStr) + : StrPtr(&InStr) { - bPassesFilter = true; - break; } - } - return bPassesFilter; + virtual bool TestBasicStringExpression(const FTextFilterString& InValue, const ETextFilterTextComparisonMode InTextComparisonMode) const override + { + return TextFilterUtils::TestBasicStringExpression(*StrPtr, InValue, InTextComparisonMode); + } + + virtual bool TestComplexExpression(const FName& InKey, const FTextFilterString& InValue, const ETextFilterComparisonOperation InComparisonOperation, const ETextFilterTextComparisonMode InTextComparisonMode) const override + { + return false; + } + + private: + const FString* StrPtr; + }; + + return InTextFilter.TestTextFilter(FClassFilterContext(InTestString)); } /** Will create the instance of FClassHierarchy and populate the class hierarchy tree. */ @@ -607,7 +617,7 @@ namespace ClassViewer * @param InInitOptions The class viewer's options, holds the AllowedClasses and DisallowedClasses. * @param InOutRootNode The node that this function will add the children of to the tree. * @param InRootClassIndex The index of the root node. - * @param InFilterSearchTerms A list of terms to filter with. + * @param InTextFilter Compiled text filter to apply. * @param bInOnlyActors Filter option to remove non-actor classes. * @param bInOnlyPlaceables Filter option to remove non-placeable classes. * @param bInOnlyBlueprintBases Filter option to remove non-blueprint base classes. @@ -615,7 +625,7 @@ namespace ClassViewer * * @return Returns true if the child passed the filter. */ - static bool AddChildren_Tree(const FClassViewerInitializationOptions& InInitOptions, TSharedPtr< FClassViewerNode >& InOutRootNode, const TSharedPtr< FClassViewerNode >& InOriginalRootNode, const TArray& InFilterSearchTerms, bool bInOnlyActors, bool bInOnlyPlaceables, bool bInOnlyBlueprintBases, bool bInShowUnloadedBlueprints ) + static bool AddChildren_Tree(const FClassViewerInitializationOptions& InInitOptions, TSharedPtr< FClassViewerNode >& InOutRootNode, const TSharedPtr< FClassViewerNode >& InOriginalRootNode, const FTextFilterExpressionEvaluator& InTextFilter, bool bInOnlyActors, bool bInOnlyPlaceables, bool bInOnlyBlueprintBases, bool bInShowUnloadedBlueprints ) { if (bInOnlyActors && *InOriginalRootNode->GetClassName().Get() != FString(TEXT("Actor"))) { @@ -645,12 +655,12 @@ namespace ClassViewer { if(bInShowUnloadedBlueprints) { - bReturnPassesFilter = InOutRootNode->bPassesFilter = bPassesPlaceableFilter && bPassesBlueprintBaseFilter && IsClassAllowed_UnloadedBlueprint(InInitOptions, InOriginalRootNode) && PassesFilter(*InOriginalRootNode->GetClassName().Get(), InFilterSearchTerms); + bReturnPassesFilter = InOutRootNode->bPassesFilter = bPassesPlaceableFilter && bPassesBlueprintBaseFilter && IsClassAllowed_UnloadedBlueprint(InInitOptions, InOriginalRootNode) && PassesFilter(*InOriginalRootNode->GetClassName().Get(), InTextFilter); } } else { - bReturnPassesFilter = InOutRootNode->bPassesFilter = bPassesPlaceableFilter && bPassesBlueprintBaseFilter && IsClassAllowed(InInitOptions, InOriginalRootNode->Class) && PassesFilter(*InOriginalRootNode->GetClassName().Get(), InFilterSearchTerms); + bReturnPassesFilter = InOutRootNode->bPassesFilter = bPassesPlaceableFilter && bPassesBlueprintBaseFilter && IsClassAllowed(InInitOptions, InOriginalRootNode->Class) && PassesFilter(*InOriginalRootNode->GetClassName().Get(), InTextFilter); } TArray< TSharedPtr< FClassViewerNode > >& ChildList = InOriginalRootNode->GetChildrenList(); @@ -658,7 +668,7 @@ namespace ClassViewer { TSharedPtr< FClassViewerNode > NewNode = MakeShareable( new FClassViewerNode( *ChildList[ChildIdx].Get() ) ); - bReturnPassesFilter |= bChildrenPassesFilter = AddChildren_Tree(InInitOptions, NewNode, ChildList[ChildIdx], InFilterSearchTerms, false, /* bInOnlyActors - false so that anything below Actor is added */ + bReturnPassesFilter |= bChildrenPassesFilter = AddChildren_Tree(InInitOptions, NewNode, ChildList[ChildIdx], InTextFilter, false, /* bInOnlyActors - false so that anything below Actor is added */ bInOnlyPlaceables, bInOnlyBlueprintBases, bInShowUnloadedBlueprints); if(bChildrenPassesFilter) { @@ -673,7 +683,7 @@ namespace ClassViewer /** Builds the class tree. * @param InInitOptions The class viewer's options, holds the AllowedClasses and DisallowedClasses. * @param InOutRootNode The node to root the tree to. - * @param InFilterSearchTerms A list of terms to filter with. + * @param InTextFilter Compiled text filter to apply. * @param bInOnlyPlaceables Filter option to remove non-placeable classes. * @param bInOnlyActors Filter option to root the tree in the "Actor" class. * @param bInOnlyBlueprintBases Filter option to remove non-blueprint base classes. @@ -681,7 +691,7 @@ namespace ClassViewer * * @return A fully built tree. */ - static void GetClassTree(const FClassViewerInitializationOptions& InInitOptions, TSharedPtr< FClassViewerNode >& InOutRootNode, const TArray& InFilterSearchTerms, bool bInOnlyPlaceables, bool bInOnlyActors, bool bInOnlyBlueprintBases, bool bInShowUnloadedBlueprints ) + static void GetClassTree(const FClassViewerInitializationOptions& InInitOptions, TSharedPtr< FClassViewerNode >& InOutRootNode, const FTextFilterExpressionEvaluator& InTextFilter, bool bInOnlyPlaceables, bool bInOnlyActors, bool bInOnlyBlueprintBases, bool bInShowUnloadedBlueprints ) { const TSharedPtr< FClassViewerNode > ObjectClassRoot = ClassHierarchy->GetObjectRootNode(); @@ -693,13 +703,13 @@ namespace ClassViewer for(int32 ClassIdx = 0; ClassIdx < ObjectClassRoot->GetChildrenList().Num(); ClassIdx++) { TSharedPtr ChildNode = MakeShareable(new FClassViewerNode(*ObjectClassRoot->GetChildrenList()[ClassIdx].Get())); - if (AddChildren_Tree(InInitOptions, ChildNode, ObjectClassRoot->GetChildrenList()[ClassIdx], InFilterSearchTerms, true, bInOnlyPlaceables, bInOnlyBlueprintBases, bInShowUnloadedBlueprints)) + if (AddChildren_Tree(InInitOptions, ChildNode, ObjectClassRoot->GetChildrenList()[ClassIdx], InTextFilter, true, bInOnlyPlaceables, bInOnlyBlueprintBases, bInShowUnloadedBlueprints)) InOutRootNode->AddChild(ChildNode); } } else { - AddChildren_Tree(InInitOptions, InOutRootNode, ObjectClassRoot, InFilterSearchTerms, false, bInOnlyPlaceables, bInOnlyBlueprintBases, bInShowUnloadedBlueprints); + AddChildren_Tree(InInitOptions, InOutRootNode, ObjectClassRoot, InTextFilter, false, bInOnlyPlaceables, bInOnlyBlueprintBases, bInShowUnloadedBlueprints); } } @@ -707,7 +717,7 @@ namespace ClassViewer * @param InInitOptions The class viewer's options, holds the AllowedClasses and DisallowedClasses. * @param InOutRootNode The node that this function will add the children of to the tree. * @param InRootClassIndex The index of the root node. - * @param InFilterSearchTerms A list of terms to filter with. + * @param InTextFilter Compiled text filter to apply. * @param bInOnlyActors Filter option to remove non-actor classes. * @param bInOnlyPlaceables Filter option to remove non-placeable classes. * @param bInOnlyBlueprintBases Filter option to remove non-blueprint base classes. @@ -715,7 +725,7 @@ namespace ClassViewer * * @return Returns true if the child passed the filter. */ - static void AddChildren_List( const FClassViewerInitializationOptions& InInitOptions, TArray< TSharedPtr< FClassViewerNode > >& InOutNodeList, const TSharedPtr< FClassViewerNode >& InOriginalRootNode, const TArray& InFilterSearchTerms, bool bInOnlyActors, bool bInOnlyPlaceables, bool bInOnlyBlueprintBases, bool bInShowUnloadedBlueprints ) + static void AddChildren_List( const FClassViewerInitializationOptions& InInitOptions, TArray< TSharedPtr< FClassViewerNode > >& InOutNodeList, const TSharedPtr< FClassViewerNode >& InOriginalRootNode, const FTextFilterExpressionEvaluator& InTextFilter, bool bInOnlyActors, bool bInOnlyPlaceables, bool bInOnlyBlueprintBases, bool bInShowUnloadedBlueprints ) { if (bInOnlyActors && *InOriginalRootNode->GetClassName().Get() != FString(TEXT("Actor"))) { @@ -743,12 +753,12 @@ namespace ClassViewer { if(bInShowUnloadedBlueprints) { - NewNode->bPassesFilter = bPassesPlaceableFilter && bPassesBlueprintBaseFilter && IsClassAllowed_UnloadedBlueprint(InInitOptions, InOriginalRootNode) && PassesFilter(*InOriginalRootNode->GetClassName().Get(), InFilterSearchTerms); + NewNode->bPassesFilter = bPassesPlaceableFilter && bPassesBlueprintBaseFilter && IsClassAllowed_UnloadedBlueprint(InInitOptions, InOriginalRootNode) && PassesFilter(*InOriginalRootNode->GetClassName().Get(), InTextFilter); } } else { - NewNode->bPassesFilter = bPassesPlaceableFilter && bPassesBlueprintBaseFilter && IsClassAllowed(InInitOptions, InOriginalRootNode->Class) && PassesFilter(*InOriginalRootNode->GetClassName().Get(), InFilterSearchTerms); + NewNode->bPassesFilter = bPassesPlaceableFilter && bPassesBlueprintBaseFilter && IsClassAllowed(InInitOptions, InOriginalRootNode->Class) && PassesFilter(*InOriginalRootNode->GetClassName().Get(), InTextFilter); } if(NewNode->bPassesFilter) @@ -761,7 +771,7 @@ namespace ClassViewer TArray< TSharedPtr< FClassViewerNode > >& ChildList = InOriginalRootNode->GetChildrenList(); for(int32 ChildIdx = 0; ChildIdx < ChildList.Num(); ChildIdx++) { - AddChildren_List(InInitOptions, InOutNodeList, ChildList[ChildIdx], InFilterSearchTerms, false, /* bInOnlyActors - false so that anything below Actor is added */ + AddChildren_List(InInitOptions, InOutNodeList, ChildList[ChildIdx], InTextFilter, false, /* bInOnlyActors - false so that anything below Actor is added */ bInOnlyPlaceables, bInOnlyBlueprintBases, bInShowUnloadedBlueprints); } } @@ -769,7 +779,7 @@ namespace ClassViewer /** Builds the class list. * @param InInitOptions The class viewer's options, holds the AllowedClasses and DisallowedClasses. * @param InOutNodeList The list to add all the nodes to. - * @param InFilterSearchTerms A list of terms to filter with. + * @param InTextFilter Compiled text filter to apply. * @param bInOnlyPlaceables Filter option to remove non-placeable classes. * @param bInOnlyActors Filter option to root the tree in the "Actor" class. * @param bInOnlyBlueprintBases Filter option to remove non-blueprint base classes. @@ -777,7 +787,7 @@ namespace ClassViewer * * @return A fully built list. */ - static void GetClassList(const FClassViewerInitializationOptions& InInitOptions, TArray< TSharedPtr< FClassViewerNode > >& InOutNodeList, const TArray& InFilterSearchTerms, bool bInOnlyPlaceables, bool bInOnlyActors, bool bInOnlyBlueprintBases, bool bInShowUnloadedBlueprints) + static void GetClassList(const FClassViewerInitializationOptions& InInitOptions, TArray< TSharedPtr< FClassViewerNode > >& InOutNodeList, const FTextFilterExpressionEvaluator& InTextFilter, bool bInOnlyPlaceables, bool bInOnlyActors, bool bInOnlyBlueprintBases, bool bInShowUnloadedBlueprints) { const TSharedPtr< FClassViewerNode > ObjectClassRoot = ClassHierarchy->GetObjectRootNode(); @@ -785,7 +795,7 @@ namespace ClassViewer if(InInitOptions.bShowObjectRootClass) { TSharedPtr< FClassViewerNode > NewNode = MakeShareable( new FClassViewerNode( *ObjectClassRoot.Get() ) ); - NewNode->bPassesFilter = IsClassAllowed(InInitOptions, ObjectClassRoot->Class) && PassesFilter(*ObjectClassRoot->GetClassName().Get(), InFilterSearchTerms); + NewNode->bPassesFilter = IsClassAllowed(InInitOptions, ObjectClassRoot->Class) && PassesFilter(*ObjectClassRoot->GetClassName().Get(), InTextFilter); if(NewNode->bPassesFilter) { @@ -798,7 +808,7 @@ namespace ClassViewer TArray< TSharedPtr< FClassViewerNode > >& ChildList = ObjectClassRoot->GetChildrenList(); for(int32 ObjectChildIndex = 0; ObjectChildIndex < ChildList.Num(); ObjectChildIndex++) { - AddChildren_List(InInitOptions, InOutNodeList, ChildList[ObjectChildIndex], InFilterSearchTerms, bInOnlyActors, bInOnlyPlaceables, bInOnlyBlueprintBases, bInShowUnloadedBlueprints); + AddChildren_List(InInitOptions, InOutNodeList, ChildList[ObjectChildIndex], InTextFilter, bInOnlyActors, bInOnlyPlaceables, bInOnlyBlueprintBases, bInShowUnloadedBlueprints); } } @@ -1924,6 +1934,8 @@ void SClassViewer::Construct(const FArguments& InArgs, const FClassViewerInitial OnClassPicked = InArgs._OnClassPickedDelegate; + TextFilterPtr = MakeShareable(new FTextFilterExpressionEvaluator(ETextFilterExpressionEvaluatorMode::BasicString)); + bSaveExpansionStates = true; bPendingSetExpansionStates = false; @@ -2367,56 +2379,9 @@ void SClassViewer::FindInContentBrowser() void SClassViewer::OnFilterTextChanged( const FText& InFilterText ) { - // If the filter was empty, we want it to save the expansion states so when it returns to empty it can restore them. - bSaveExpansionStates = !FilterSearchTerms.Num(); - - FilterSearchTerms.Empty(); - - FString CurrentFilterText = InFilterText.ToString(); - - // Sanitize, parse and split the filter text into search terms - CurrentFilterText.Trim().TrimTrailing(); - //FilterSearchTerms.Reset(); - { - bool bIsWithinQuotedSection = false; - FString NewSearchTerm; - for( auto CurChar : CurrentFilterText ) - { - // Keep an eye out for double-quotes. We want to retain whitespace within a search term if - // it has double-quotes around it - if( CurChar == TCHAR('\"') ) - { - // Toggle whether we're within a quoted section, but don't bother adding the quote character - bIsWithinQuotedSection = !bIsWithinQuotedSection; - } - else if( bIsWithinQuotedSection || !FChar::IsWhitespace( CurChar ) ) - { - // Add the character! - NewSearchTerm.AppendChar( CurChar ); - } - else - { - // Encountered whitespace, so add the search term up to here - if( NewSearchTerm.Len() > 0 ) - { - FilterSearchTerms.Add( NewSearchTerm ); - NewSearchTerm = FString(); - } - } - } - - // Encountered EOL, so add the search term up to here - if( NewSearchTerm.Len() > 0 ) - { - FilterSearchTerms.Add( NewSearchTerm ); - NewSearchTerm = FString(); - } - - if( bIsWithinQuotedSection ) - { - // User forgot to terminate their double-quoted section. No big deal. - } - } + // Update the compiled filter and report any syntax error information back to the user + TextFilterPtr->SetFilterText(InFilterText); + SearchBox->SetError(TextFilterPtr->GetFilterErrorText()); // Repopulate the list to show only what has not been filtered out. Refresh(); @@ -2644,10 +2609,10 @@ void SClassViewer::Populate() TSharedPtr RootNode; // Get the class tree, passing in certain filter options. - ClassViewer::Helpers::GetClassTree(InitOptions, RootNode, FilterSearchTerms, MenuPlaceableOnly_IsChecked(), MenuActorsOnly_IsChecked(), MenuBlueprintBasesOnly_IsChecked(), bShowUnloadedBlueprints ); + ClassViewer::Helpers::GetClassTree(InitOptions, RootNode, *TextFilterPtr, MenuPlaceableOnly_IsChecked(), MenuActorsOnly_IsChecked(), MenuBlueprintBasesOnly_IsChecked(), bShowUnloadedBlueprints ); // Check if we will restore expansion states, we will not if there is filtering happening. - const bool bRestoreExpansionState = !FilterSearchTerms.Num(); + const bool bRestoreExpansionState = TextFilterPtr->GetFilterType() == ETextFilterExpressionType::Empty; if(InitOptions.bShowObjectRootClass) { @@ -2659,7 +2624,7 @@ void SClassViewer::Populate() } // Expand any items that pass the filter. - if(FilterSearchTerms.Num() > 0) + if(TextFilterPtr->GetFilterType() != ETextFilterExpressionType::Empty) { ExpandFilteredInNodes(RootNode); } @@ -2676,7 +2641,7 @@ void SClassViewer::Populate() } // Expand any items that pass the filter. - if(FilterSearchTerms.Num() > 0) + if(TextFilterPtr->GetFilterType() != ETextFilterExpressionType::Empty) { ExpandFilteredInNodes(RootNode->GetChildrenList()[ChildIndex]); } @@ -2697,7 +2662,7 @@ void SClassViewer::Populate() else { // Get the class list, passing in certain filter options. - ClassViewer::Helpers::GetClassList(InitOptions, RootTreeItems, FilterSearchTerms, MenuPlaceableOnly_IsChecked(), MenuActorsOnly_IsChecked(), MenuBlueprintBasesOnly_IsChecked(), bShowUnloadedBlueprints); + ClassViewer::Helpers::GetClassList(InitOptions, RootTreeItems, *TextFilterPtr, MenuPlaceableOnly_IsChecked(), MenuActorsOnly_IsChecked(), MenuBlueprintBasesOnly_IsChecked(), bShowUnloadedBlueprints); // Sort the list alphabetically. struct FCompareFClassViewerNode diff --git a/Engine/Source/Editor/ClassViewer/Private/SClassViewer.h b/Engine/Source/Editor/ClassViewer/Private/SClassViewer.h index 460ff5b2429e..11e94afe892d 100644 --- a/Engine/Source/Editor/ClassViewer/Private/SClassViewer.h +++ b/Engine/Source/Editor/ClassViewer/Private/SClassViewer.h @@ -8,6 +8,7 @@ // SClassViewer class FClassViewerNode; +class FTextFilterExpressionEvaluator; class SClassViewer : public SCompoundWidget { @@ -170,8 +171,8 @@ private: /** The items to be displayed in the tree. */ TArray< TSharedPtr< FClassViewerNode > > RootTreeItems; - /** Split and sanitized list of filter search terms. Cached for faster search performance. */ - TArray< FString > FilterSearchTerms; + /** Compiled filter search terms. */ + TSharedPtr TextFilterPtr; /** Holds the Slate Tree widget which holds the classes for the Class Viewer. */ TSharedPtr >> ClassTree; diff --git a/Engine/Source/Editor/ContentBrowser/Private/AssetContextMenu.cpp b/Engine/Source/Editor/ContentBrowser/Private/AssetContextMenu.cpp index d1f577c928e1..966190d2e9f5 100644 --- a/Engine/Source/Editor/ContentBrowser/Private/AssetContextMenu.cpp +++ b/Engine/Source/Editor/ContentBrowser/Private/AssetContextMenu.cpp @@ -17,6 +17,7 @@ #include "ISizeMapModule.h" #include "ReferencedAssetsUtils.h" +#include "PackageLocalizationUtil.h" #include "ISourceControlModule.h" #include "ISourceControlRevision.h" @@ -209,10 +210,26 @@ bool FAssetContextMenu::AddImportedAssetMenuOptions(FMenuBuilder& MenuBuilder) bool FAssetContextMenu::AddCommonMenuOptions(FMenuBuilder& MenuBuilder) { - TArray< FAssetData > AssetViewSelectedAssets = AssetView.Pin()->GetSelectedAssets(); - int32 NumAssetItems, NumClassItems; - ContentBrowserUtils::CountItemTypes(AssetViewSelectedAssets, NumAssetItems, NumClassItems); + ContentBrowserUtils::CountItemTypes(SelectedAssets, NumAssetItems, NumClassItems); + + FAssetToolsModule& AssetToolsModule = FModuleManager::Get().LoadModuleChecked("AssetTools"); + + // Can any of the selected assets be localized? + bool bAnyLocalizableAssetsSelected = false; + for (const FAssetData& Asset : SelectedAssets) + { + TSharedPtr AssetTypeActions = AssetToolsModule.Get().GetAssetTypeActionsForClass(Asset.GetClass()).Pin(); + if (AssetTypeActions.IsValid()) + { + bAnyLocalizableAssetsSelected = AssetTypeActions->CanLocalize(); + } + + if (bAnyLocalizableAssetsSelected) + { + break; + } + } MenuBuilder.BeginSection("CommonAssetActions", LOCTEXT("CommonAssetActionsMenuHeading", "Common")); { @@ -273,6 +290,21 @@ bool FAssetContextMenu::AddCommonMenuOptions(FMenuBuilder& MenuBuilder) false, FSlateIcon(FEditorStyle::GetStyleSetName(), "ContentBrowser.AssetActions") ); + + if (bAnyLocalizableAssetsSelected && NumClassItems == 0) + { + // Asset Localization sub-menu + MenuBuilder.AddSubMenu( + LOCTEXT("LocalizationSubMenuLabel", "Asset Localization"), + LOCTEXT("LocalizationSubMenuToolTip", "View or create localized variants of this asset"), + FNewMenuDelegate::CreateSP(this, &FAssetContextMenu::MakeAssetLocalizationSubMenu), + FUIAction(), + NAME_None, + EUserInterfaceActionType::Button, + false, + FSlateIcon(FEditorStyle::GetStyleSetName(), "ContentBrowser.AssetLocalization") + ); + } } } MenuBuilder.EndSection(); @@ -470,6 +502,318 @@ bool FAssetContextMenu::CanExecuteAssetActions() const return !bAtLeastOneClassSelected; } +void FAssetContextMenu::MakeAssetLocalizationSubMenu(FMenuBuilder& MenuBuilder) +{ + TArray CurrentCultures; + + // Build up the list of cultures already used + { + TSet CulturePaths; + + bool bIncludeEngineCultures = false; + bool bIncludeProjectCultures = false; + + for (const FAssetData& Asset : SelectedAssets) + { + const FString AssetPath = Asset.ObjectPath.ToString(); + + if (ContentBrowserUtils::IsEngineFolder(AssetPath)) + { + bIncludeEngineCultures = true; + } + else + { + bIncludeProjectCultures = true; + } + + { + FString AssetLocalizationRoot; + if (FPackageLocalizationUtil::GetLocalizedRoot(AssetPath, FString(), AssetLocalizationRoot)) + { + FString AssetLocalizationFileRoot; + if (FPackageName::TryConvertLongPackageNameToFilename(AssetLocalizationRoot, AssetLocalizationFileRoot)) + { + CulturePaths.Add(MoveTemp(AssetLocalizationFileRoot)); + } + } + } + } + + if (bIncludeEngineCultures) + { + CulturePaths.Append(FPaths::GetEngineLocalizationPaths()); + } + + if (bIncludeProjectCultures) + { + CulturePaths.Append(FPaths::GetGameLocalizationPaths()); + } + + FInternationalization::Get().GetCulturesWithAvailableLocalization(CulturePaths.Array(), CurrentCultures, false); + + if (CurrentCultures.Num() == 0) + { + CurrentCultures.Add(FInternationalization::Get().GetCurrentCulture()); + } + } + + // Sort by display name for the UI + CurrentCultures.Sort([](const FCultureRef& FirstCulture, const FCultureRef& SecondCulture) -> bool + { + const FText FirstDisplayName = FText::FromString(FirstCulture->GetDisplayName()); + const FText SecondDisplayName = FText::FromString(SecondCulture->GetDisplayName()); + return FirstDisplayName.CompareTo(SecondDisplayName) < 0; + }); + + FAssetToolsModule& AssetToolsModule = FModuleManager::Get().LoadModuleChecked("AssetTools"); + + // Now build up the list of available localized or source assets based upon the current selection and current cultures + FSourceAssetsState SourceAssetsState; + TArray LocalizedAssetsState; + for (const FCultureRef& CurrentCulture : CurrentCultures) + { + FLocalizedAssetsState& LocalizedAssetsStateForCulture = LocalizedAssetsState[LocalizedAssetsState.AddDefaulted()]; + LocalizedAssetsStateForCulture.Culture = CurrentCulture; + + for (const FAssetData& Asset : SelectedAssets) + { + // Can this type of asset be localized? + bool bCanLocalizeAsset = false; + { + TSharedPtr AssetTypeActions = AssetToolsModule.Get().GetAssetTypeActionsForClass(Asset.GetClass()).Pin(); + if (AssetTypeActions.IsValid()) + { + bCanLocalizeAsset = AssetTypeActions->CanLocalize(); + } + } + + if (!bCanLocalizeAsset) + { + continue; + } + + const FString ObjectPath = Asset.ObjectPath.ToString(); + if (FPackageName::IsLocalizedPackage(ObjectPath)) + { + // Get the source path for this asset + FString SourceObjectPath; + if (FPackageLocalizationUtil::ConvertLocalizedToSource(ObjectPath, SourceObjectPath)) + { + SourceAssetsState.CurrentAssets.Add(*SourceObjectPath); + } + } + else + { + SourceAssetsState.SelectedAssets.Add(Asset.ObjectPath); + + // Get the localized path for this asset and culture + FString LocalizedObjectPath; + if (FPackageLocalizationUtil::ConvertSourceToLocalized(ObjectPath, CurrentCulture->GetName(), LocalizedObjectPath)) + { + // Does this localized asset already exist? + FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked(TEXT("AssetRegistry")); + FAssetData LocalizedAssetData = AssetRegistryModule.Get().GetAssetByObjectPath(*LocalizedObjectPath); + + if (LocalizedAssetData.IsValid()) + { + LocalizedAssetsStateForCulture.CurrentAssets.Add(*LocalizedObjectPath); + } + else + { + LocalizedAssetsStateForCulture.NewAssets.Add(*LocalizedObjectPath); + } + } + } + } + } + + // If we found source assets for localized assets, then we can show the Source Asset options + if (SourceAssetsState.CurrentAssets.Num() > 0) + { + MenuBuilder.BeginSection(NAME_None, LOCTEXT("ManageSourceAssetHeading", "Manage Source Asset")); + { + MenuBuilder.AddMenuEntry( + LOCTEXT("ShowSourceAsset", "Show Source Asset"), + LOCTEXT("ShowSourceAssetTooltip", "Show the source asset in the Content Browser."), + FSlateIcon(FEditorStyle::GetStyleSetName(), "SystemWideCommands.FindInContentBrowser"), + FUIAction(FExecuteAction::CreateSP(this, &FAssetContextMenu::ExecuteFindInAssetTree, SourceAssetsState.CurrentAssets.Array())) + ); + + MenuBuilder.AddMenuEntry( + LOCTEXT("EditSourceAsset", "Edit Source Asset"), + LOCTEXT("EditSourceAssetTooltip", "Edit the source asset."), + FSlateIcon(FEditorStyle::GetStyleSetName(), "ContentBrowser.AssetActions.Edit"), + FUIAction(FExecuteAction::CreateSP(this, &FAssetContextMenu::ExecuteOpenEditorsForAssets, SourceAssetsState.CurrentAssets.Array())) + ); + } + MenuBuilder.EndSection(); + } + + // If we currently have source assets selected, then we can show the Localized Asset options + if (SourceAssetsState.SelectedAssets.Num() > 0) + { + MenuBuilder.BeginSection(NAME_None, LOCTEXT("ManageLocalizedAssetHeading", "Manage Localized Asset")); + { + MenuBuilder.AddSubMenu( + LOCTEXT("CreateLocalizedAsset", "Create Localized Asset"), + LOCTEXT("CreateLocalizedAssetTooltip", "Create a new localized asset."), + FNewMenuDelegate::CreateSP(this, &FAssetContextMenu::MakeCreateLocalizedAssetSubMenu, SourceAssetsState.SelectedAssets, LocalizedAssetsState), + FUIAction(), + NAME_None, + EUserInterfaceActionType::Button, + false, + FSlateIcon(FEditorStyle::GetStyleSetName(), "ContentBrowser.AssetActions.Duplicate") + ); + + int32 NumLocalizedAssets = 0; + for (const FLocalizedAssetsState& LocalizedAssetsStateForCulture : LocalizedAssetsState) + { + NumLocalizedAssets += LocalizedAssetsStateForCulture.CurrentAssets.Num(); + } + + if (NumLocalizedAssets > 0) + { + MenuBuilder.AddSubMenu( + LOCTEXT("ShowLocalizedAsset", "Show Localized Asset"), + LOCTEXT("ShowLocalizedAssetTooltip", "Show the localized asset in the Content Browser."), + FNewMenuDelegate::CreateSP(this, &FAssetContextMenu::MakeShowLocalizedAssetSubMenu, LocalizedAssetsState), + FUIAction(), + NAME_None, + EUserInterfaceActionType::Button, + false, + FSlateIcon(FEditorStyle::GetStyleSetName(), "SystemWideCommands.FindInContentBrowser") + ); + + MenuBuilder.AddSubMenu( + LOCTEXT("EditLocalizedAsset", "Edit Localized Asset"), + LOCTEXT("EditLocalizedAssetTooltip", "Edit the localized asset."), + FNewMenuDelegate::CreateSP(this, &FAssetContextMenu::MakeEditLocalizedAssetSubMenu, LocalizedAssetsState), + FUIAction(), + NAME_None, + EUserInterfaceActionType::Button, + false, + FSlateIcon(FEditorStyle::GetStyleSetName(), "ContentBrowser.AssetActions.Edit") + ); + } + } + MenuBuilder.EndSection(); + } +} + +void FAssetContextMenu::MakeCreateLocalizedAssetSubMenu(FMenuBuilder& MenuBuilder, TSet InSelectedSourceAssets, TArray InLocalizedAssetsState) +{ + for (const FLocalizedAssetsState& LocalizedAssetsStateForCulture : InLocalizedAssetsState) + { + // If we have less localized assets than we have selected source assets, then we'll have some assets to create localized variants of + if (LocalizedAssetsStateForCulture.CurrentAssets.Num() < InSelectedSourceAssets.Num()) + { + MenuBuilder.AddMenuEntry( + FText::FromString(LocalizedAssetsStateForCulture.Culture->GetDisplayName()), + FText::GetEmpty(), + FSlateIcon(), + FUIAction(FExecuteAction::CreateSP(this, &FAssetContextMenu::ExecuteCreateLocalizedAsset, InSelectedSourceAssets, LocalizedAssetsStateForCulture)) + ); + } + } +} + +void FAssetContextMenu::MakeShowLocalizedAssetSubMenu(FMenuBuilder& MenuBuilder, TArray InLocalizedAssetsState) +{ + for (const FLocalizedAssetsState& LocalizedAssetsStateForCulture : InLocalizedAssetsState) + { + if (LocalizedAssetsStateForCulture.CurrentAssets.Num() > 0) + { + MenuBuilder.AddMenuEntry( + FText::FromString(LocalizedAssetsStateForCulture.Culture->GetDisplayName()), + FText::GetEmpty(), + FSlateIcon(), + FUIAction(FExecuteAction::CreateSP(this, &FAssetContextMenu::ExecuteFindInAssetTree, LocalizedAssetsStateForCulture.CurrentAssets.Array())) + ); + } + } +} + +void FAssetContextMenu::MakeEditLocalizedAssetSubMenu(FMenuBuilder& MenuBuilder, TArray InLocalizedAssetsState) +{ + for (const FLocalizedAssetsState& LocalizedAssetsStateForCulture : InLocalizedAssetsState) + { + if (LocalizedAssetsStateForCulture.CurrentAssets.Num() > 0) + { + MenuBuilder.AddMenuEntry( + FText::FromString(LocalizedAssetsStateForCulture.Culture->GetDisplayName()), + FText::GetEmpty(), + FSlateIcon(), + FUIAction(FExecuteAction::CreateSP(this, &FAssetContextMenu::ExecuteOpenEditorsForAssets, LocalizedAssetsStateForCulture.CurrentAssets.Array())) + ); + } + } +} + +void FAssetContextMenu::ExecuteCreateLocalizedAsset(TSet InSelectedSourceAssets, FLocalizedAssetsState InLocalizedAssetsStateForCulture) +{ + TArray PackagesToSave; + TArray NewObjects; + + for (const FName SourceAssetName : InSelectedSourceAssets) + { + if (InLocalizedAssetsStateForCulture.CurrentAssets.Contains(SourceAssetName)) + { + // Asset is already localized + continue; + } + + UObject* SourceAssetObject = LoadObject(nullptr, *SourceAssetName.ToString()); + if (!SourceAssetObject) + { + // Source object cannot be loaded + continue; + } + + FString LocalizedPackageName; + if (!FPackageLocalizationUtil::ConvertSourceToLocalized(SourceAssetObject->GetOutermost()->GetPathName(), InLocalizedAssetsStateForCulture.Culture->GetName(), LocalizedPackageName)) + { + continue; + } + + ObjectTools::FPackageGroupName NewAssetName; + NewAssetName.PackageName = LocalizedPackageName; + NewAssetName.ObjectName = SourceAssetObject->GetName(); + + TSet PackagesNotDuplicated; + UObject* NewObject = ObjectTools::DuplicateSingleObject(SourceAssetObject, NewAssetName, PackagesNotDuplicated); + if (NewObject) + { + PackagesToSave.Add(NewObject->GetOutermost()); + NewObjects.Add(FAssetData(NewObject)); + } + } + + if (PackagesToSave.Num() > 0) + { + FEditorFileUtils::PromptForCheckoutAndSave(PackagesToSave, /*bCheckDirty*/false, /*bPromptToSave*/false); + } + + OnFindInAssetTreeRequested.ExecuteIfBound(NewObjects); +} + +void FAssetContextMenu::ExecuteFindInAssetTree(TArray InAssets) +{ + FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked(TEXT("AssetRegistry")); + + FARFilter ARFilter; + ARFilter.ObjectPaths = MoveTemp(InAssets); + + TArray FoundLocalizedAssetData; + AssetRegistryModule.Get().GetAssets(ARFilter, FoundLocalizedAssetData); + + OnFindInAssetTreeRequested.ExecuteIfBound(FoundLocalizedAssetData); +} + +void FAssetContextMenu::ExecuteOpenEditorsForAssets(TArray InAssets) +{ + FAssetEditorManager::Get().OpenEditorsForAssets(InAssets); +} + bool FAssetContextMenu::AddReferenceMenuOptions(FMenuBuilder& MenuBuilder) { MenuBuilder.BeginSection("AssetContextReferences", LOCTEXT("ReferencesMenuHeading", "References")); diff --git a/Engine/Source/Editor/ContentBrowser/Private/AssetContextMenu.h b/Engine/Source/Editor/ContentBrowser/Private/AssetContextMenu.h index 8309ee3b2215..3a5965e11a1f 100644 --- a/Engine/Source/Editor/ContentBrowser/Private/AssetContextMenu.h +++ b/Engine/Source/Editor/ContentBrowser/Private/AssetContextMenu.h @@ -48,6 +48,20 @@ public: /** Handler for Delete */ void ExecuteDelete(); +private: + struct FSourceAssetsState + { + TSet SelectedAssets; + TSet CurrentAssets; + }; + + struct FLocalizedAssetsState + { + FCulturePtr Culture; + TSet NewAssets; + TSet CurrentAssets; + }; + private: /** Helper to load selected assets and sort them by UClass */ void GetSelectedAssetsByClass(TMap >& OutSelectedAssetsByClass) const; @@ -95,6 +109,27 @@ private: /** Handler to check to see if "Asset Actions" are allowed */ bool CanExecuteAssetActions() const; + /** Adds Asset Localization sub-menu to a menu builder. */ + void MakeAssetLocalizationSubMenu(FMenuBuilder& MenuBuilder); + + /** Adds the Create Localized Asset sub-menu to a menu builder. */ + void MakeCreateLocalizedAssetSubMenu(FMenuBuilder& MenuBuilder, TSet InSelectedSourceAssets, TArray InLocalizedAssetsState); + + /** Adds the Show Localized Assets sub-menu to a menu builder. */ + void MakeShowLocalizedAssetSubMenu(FMenuBuilder& MenuBuilder, TArray InLocalizedAssetsState); + + /** Adds the Edit Localized Assets sub-menu to a menu builder. */ + void MakeEditLocalizedAssetSubMenu(FMenuBuilder& MenuBuilder, TArray InLocalizedAssetsState); + + /** Create new localized assets for the given culture */ + void ExecuteCreateLocalizedAsset(TSet InSelectedSourceAssets, FLocalizedAssetsState InLocalizedAssetsStateForCulture); + + /** Find the given assets in the Content Browser */ + void ExecuteFindInAssetTree(TArray InAssets); + + /** Open the given assets in their respective editors */ + void ExecuteOpenEditorsForAssets(TArray InAssets); + /** Adds asset reference menu options to a menu builder. Returns true if any options were added. */ bool AddReferenceMenuOptions(FMenuBuilder& MenuBuilder); diff --git a/Engine/Source/Editor/ContentBrowser/Private/SAssetView.cpp b/Engine/Source/Editor/ContentBrowser/Private/SAssetView.cpp index 1c20f88d885d..17d81b54c253 100644 --- a/Engine/Source/Editor/ContentBrowser/Private/SAssetView.cpp +++ b/Engine/Source/Editor/ContentBrowser/Private/SAssetView.cpp @@ -1373,41 +1373,42 @@ static bool IsValidObjectPath(const FString& Path) FReply SAssetView::OnKeyDown( const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent ) { + if (InKeyEvent.IsControlDown() && InKeyEvent.GetCharacter() == 'V' && IsAssetPathSelected()) { - const bool bTestOnly = true; - if ( InKeyEvent.IsControlDown() && InKeyEvent.GetCharacter() == 'V' && IsAssetPathSelected() ) + FString AssetPaths; + TArray AssetPathsSplit; + + // Get the copied asset paths + FPlatformMisc::ClipboardPaste(AssetPaths); + AssetPaths.ParseIntoArrayLines(AssetPathsSplit); + + // Get assets and copy them + TArray AssetsToCopy; + for (const FString& AssetPath : AssetPathsSplit) { - FString DestPaths; - TArray DestPathsSplit; - - // Get the copied asset paths - FPlatformMisc::ClipboardPaste( DestPaths ); - DestPaths.ParseIntoArrayLines( DestPathsSplit ); - - // Get assets and copy them - TArray ObjectsToCopy; - for (FString DestPath : DestPathsSplit) + // Validate string + if (IsValidObjectPath(AssetPath)) { - // Validate string - if ( IsValidObjectPath(DestPath) ) + UObject* ObjectToCopy = LoadObject(nullptr, *AssetPath); + if (ObjectToCopy && !ObjectToCopy->IsA(UClass::StaticClass())) { - ObjectsToCopy.Add( LoadObject( NULL, *DestPath )); + AssetsToCopy.Add(ObjectToCopy); } } - - if (ObjectsToCopy.Num()) - { - ContentBrowserUtils::CopyAssets(ObjectsToCopy, SourcesData.PackagePaths[0].ToString()); - } - - return FReply::Handled(); } - // Swallow the key-presses used by the quick-jump in OnKeyChar to avoid other things (such as the viewport commands) getting them instead - // eg) Pressing "W" without this would set the viewport to "translate" mode - else if( HandleQuickJumpKeyDown(InKeyEvent.GetCharacter(), InKeyEvent.IsControlDown(), InKeyEvent.IsAltDown(), bTestOnly).IsEventHandled() ) + + if (AssetsToCopy.Num()) { - return FReply::Handled(); + ContentBrowserUtils::CopyAssets(AssetsToCopy, SourcesData.PackagePaths[0].ToString()); } + + return FReply::Handled(); + } + // Swallow the key-presses used by the quick-jump in OnKeyChar to avoid other things (such as the viewport commands) getting them instead + // eg) Pressing "W" without this would set the viewport to "translate" mode + else if(HandleQuickJumpKeyDown(InKeyEvent.GetCharacter(), InKeyEvent.IsControlDown(), InKeyEvent.IsAltDown(), /*bTestOnly*/true).IsEventHandled()) + { + return FReply::Handled(); } return FReply::Unhandled(); diff --git a/Engine/Source/Editor/ContentBrowser/Private/SContentBrowser.cpp b/Engine/Source/Editor/ContentBrowser/Private/SContentBrowser.cpp index 8a220328c0ab..407aa2618c56 100644 --- a/Engine/Source/Editor/ContentBrowser/Private/SContentBrowser.cpp +++ b/Engine/Source/Editor/ContentBrowser/Private/SContentBrowser.cpp @@ -789,10 +789,11 @@ void SContentBrowser::SyncToAssets( const TArray& AssetDataList, con bool bDisplayDev = GetDefault()->GetDisplayDevelopersFolder(); bool bDisplayEngine = GetDefault()->GetDisplayEngineFolder(); bool bDisplayPlugins = GetDefault()->GetDisplayPluginFolders(); - if ( !bDisplayDev || !bDisplayEngine || !bDisplayPlugins ) + bool bDisplayLocalized = GetDefault()->GetDisplayL10NFolder(); + if ( !bDisplayDev || !bDisplayEngine || !bDisplayPlugins || !bDisplayLocalized ) { bool bRepopulate = false; - for (int32 AssetIdx = AssetDataList.Num() - 1; AssetIdx >= 0 && ( !bDisplayDev || !bDisplayEngine || !bDisplayPlugins ); --AssetIdx) + for (int32 AssetIdx = AssetDataList.Num() - 1; AssetIdx >= 0 && ( !bDisplayDev || !bDisplayEngine || !bDisplayPlugins || !bDisplayLocalized ); --AssetIdx) { const FAssetData& Item = AssetDataList[AssetIdx]; @@ -828,6 +829,13 @@ void SContentBrowser::SyncToAssets( const TArray& AssetDataList, con GetMutableDefault()->SetDisplayPluginFolders(true, true); bRepopulate = true; } + + if (!bDisplayLocalized && ContentBrowserUtils::IsLocalizationFolder(PackagePath)) + { + bDisplayLocalized = true; + GetMutableDefault()->SetDisplayL10NFolder(true); + bRepopulate = true; + } } // If we have auto-enabled any flags, force a refresh diff --git a/Engine/Source/Editor/ContentBrowser/Private/SPathView.cpp b/Engine/Source/Editor/ContentBrowser/Private/SPathView.cpp index b5fb3bd640e2..5b75e53c1e94 100644 --- a/Engine/Source/Editor/ContentBrowser/Private/SPathView.cpp +++ b/Engine/Source/Editor/ContentBrowser/Private/SPathView.cpp @@ -638,10 +638,11 @@ void SPathView::LoadSettings(const FString& IniFilename, const FString& IniSecti // Send the first selected item with the notification const TArray> SelectedItems = TreeViewPtr->GetSelectedItems(); - check(SelectedItems.Num() > 0); - - // Signal a single selection changed event to let any listeners know that paths have changed - TreeSelectionChanged( SelectedItems[0], ESelectInfo::Direct ); + if (SelectedItems.Num() > 0) + { + // Signal a single selection changed event to let any listeners know that paths have changed + TreeSelectionChanged( SelectedItems[0], ESelectInfo::Direct ); + } } } } diff --git a/Engine/Source/Editor/DetailCustomizations/Private/CurveStructCustomization.cpp b/Engine/Source/Editor/DetailCustomizations/Private/CurveStructCustomization.cpp index 2a791a12f380..68c24a69dca6 100644 --- a/Engine/Source/Editor/DetailCustomizations/Private/CurveStructCustomization.cpp +++ b/Engine/Source/Editor/DetailCustomizations/Private/CurveStructCustomization.cpp @@ -41,7 +41,6 @@ void FCurveStructCustomization::CustomizeHeader( TSharedRef InS TArray StructPtrs; StructPropertyHandle->AccessRawData( StructPtrs ); - check(StructPtrs.Num()!=0); if (StructPtrs.Num() == 1) { @@ -70,7 +69,7 @@ void FCurveStructCustomization::CustomizeHeader( TSharedRef InS HeaderRow .NameContent() [ - InStructPropertyHandle->CreatePropertyNameWidget( FText::GetEmpty(), FText::GetEmpty(), false ) + InStructPropertyHandle->CreatePropertyNameWidget() ] .ValueContent() .HAlign(HAlign_Fill) @@ -107,7 +106,7 @@ void FCurveStructCustomization::CustomizeHeader( TSharedRef InS HeaderRow .NameContent() [ - InStructPropertyHandle->CreatePropertyNameWidget( FText::GetEmpty(), FText::GetEmpty(), false ) + InStructPropertyHandle->CreatePropertyNameWidget() ] .ValueContent() [ @@ -115,7 +114,7 @@ void FCurveStructCustomization::CustomizeHeader( TSharedRef InS .VAlign(VAlign_Fill) [ SNew(STextBlock) - .Text(LOCTEXT("MultipleCurves", "Multiple Curves - unable to modify")) + .Text(StructPtrs.Num() == 0 ? LOCTEXT("NoCurves", "No Curves - unable to modify") : LOCTEXT("MultipleCurves", "Multiple Curves - unable to modify")) ] ]; } diff --git a/Engine/Source/Editor/DetailCustomizations/Private/TextCustomization.cpp b/Engine/Source/Editor/DetailCustomizations/Private/TextCustomization.cpp index 503c40732a6d..ea6e7b58d3ab 100644 --- a/Engine/Source/Editor/DetailCustomizations/Private/TextCustomization.cpp +++ b/Engine/Source/Editor/DetailCustomizations/Private/TextCustomization.cpp @@ -46,33 +46,38 @@ namespace virtual int32 GetNumTexts() const override { - const TArray& RawTextData = SyncRawTextData(); - return (PropertyHandle->IsValidHandle()) - ? RawTextData.Num() + ? PropertyHandle->GetNumPerObjectValues() : 0; } virtual FText GetText(const int32 InIndex) const override { - const TArray& RawTextData = SyncRawTextData(); - if (PropertyHandle->IsValidHandle()) { - check(RawTextData.IsValidIndex(InIndex)); - return *RawTextData[InIndex]; + FString ObjectValue; + if (PropertyHandle->GetPerObjectValue(InIndex, ObjectValue) == FPropertyAccess::Success) + { + FText TextValue; + if (FTextStringHelper::ReadFromString(*ObjectValue, TextValue)) + { + return TextValue; + } + } } + return FText::GetEmpty(); } virtual void SetText(const int32 InIndex, const FText& InText) override { - const TArray& RawTextData = SyncRawTextData(); - if (PropertyHandle->IsValidHandle()) { - check(RawTextData.IsValidIndex(InIndex)); - *RawTextData[InIndex] = InText; + FString ObjectValue; + if (FTextStringHelper::WriteToString(ObjectValue, InText)) + { + PropertyHandle->SetPerObjectValue(InIndex, ObjectValue); + } } } @@ -102,26 +107,8 @@ namespace } private: - const TArray& SyncRawTextData() const - { - // Sync the scratch data array with the current property data - RawTextDataScratchArray.Reset(); - - if (PropertyHandle->IsValidHandle()) - { - PropertyHandle->EnumerateRawData([&](void* RawData, const int32 DataIndex, const int32 NumDatas) -> bool - { - RawTextDataScratchArray.Add(static_cast(RawData)); - return true; - }); - } - - return RawTextDataScratchArray; - } - TSharedRef PropertyHandle; TSharedPtr PropertyUtilities; - mutable TArray RawTextDataScratchArray; }; } diff --git a/Engine/Source/Editor/DistCurveEditor/Private/CurveEditorViewportClient.cpp b/Engine/Source/Editor/DistCurveEditor/Private/CurveEditorViewportClient.cpp index b4f6683359d6..7a60f86b8521 100644 --- a/Engine/Source/Editor/DistCurveEditor/Private/CurveEditorViewportClient.cpp +++ b/Engine/Source/Editor/DistCurveEditor/Private/CurveEditorViewportClient.cpp @@ -403,10 +403,10 @@ bool FCurveEditorViewportClient::InputKey(FViewport* Viewport, int32 ControllerI { if(bBoxSelecting) { - int32 MinX = FMath::Min(BoxStartX, BoxEndX); - int32 MinY = FMath::Min(BoxStartY, BoxEndY); - int32 MaxX = FMath::Max(BoxStartX, BoxEndX); - int32 MaxY = FMath::Max(BoxStartY, BoxEndY); + int32 MinX = FMath::Max(0, FMath::Min(BoxStartX, BoxEndX)); + int32 MinY = FMath::Max(0, FMath::Min(BoxStartY, BoxEndY)); + int32 MaxX = FMath::Min(Viewport->GetSizeXY().X - 1, FMath::Max(BoxStartX, BoxEndX)); + int32 MaxY = FMath::Min(Viewport->GetSizeXY().Y - 1, FMath::Max(BoxStartY, BoxEndY)); int32 TestSizeX = MaxX - MinX + 1; int32 TestSizeY = MaxY - MinY + 1; diff --git a/Engine/Source/Editor/EditorStyle/Private/SlateEditorStyle.cpp b/Engine/Source/Editor/EditorStyle/Private/SlateEditorStyle.cpp index 2975a7f0de92..da74f68fe550 100644 --- a/Engine/Source/Editor/EditorStyle/Private/SlateEditorStyle.cpp +++ b/Engine/Source/Editor/EditorStyle/Private/SlateEditorStyle.cpp @@ -1524,7 +1524,8 @@ void FSlateEditorStyle::FStyle::SetupGeneralStyles() .SetNormalBarImage(FSlateColorBrush(FColor::White)) .SetDisabledBarImage(FSlateColorBrush(FLinearColor::Gray)) .SetNormalThumbImage( BOX_BRUSH( "Common/Button", 8.0f/32.0f ) ) - .SetDisabledThumbImage( BOX_BRUSH( "Common/Button_Disabled", 8.0f/32.0f ) ); + .SetDisabledThumbImage( BOX_BRUSH( "Common/Button_Disabled", 8.0f/32.0f ) ) + .SetBarThickness(2.0f); Set( "Slider", SliderStyle ); Set( "VolumeControl", FVolumeControlStyle() @@ -5838,6 +5839,7 @@ void FSlateEditorStyle::FStyle::SetupContentBrowserStyle() Set( "ContentBrowser.AssetActions.CreateThumbnail", new IMAGE_BRUSH( "Icons/icon_Asset_Create_Thumbnail_16x", Icon16x16) ); Set( "ContentBrowser.AssetActions.DeleteThumbnail", new IMAGE_BRUSH( "Icons/icon_Asset_Delete_Thumbnail_16x", Icon16x16) ); Set( "ContentBrowser.AssetActions.GenericFind", new IMAGE_BRUSH( "Icons/icon_Genericfinder_16x", Icon16x16) ); + Set( "ContentBrowser.AssetLocalization", new IMAGE_BRUSH( "Icons/icon_localization_16x", Icon16x16 ) ); Set( "MediaAsset.AssetActions.Play", new IMAGE_BRUSH( "Icons/icon_SCueEd_PlayCue_16x", Icon16x16 ) ); Set( "MediaAsset.AssetActions.Stop", new IMAGE_BRUSH( "Icons/icon_SCueEd_Stop_16x", Icon16x16 ) ); diff --git a/Engine/Source/Editor/GraphEditor/Private/KismetNodes/SGraphNodeK2CreateDelegate.cpp b/Engine/Source/Editor/GraphEditor/Private/KismetNodes/SGraphNodeK2CreateDelegate.cpp index 2fc9513be467..1f3623c19ed4 100644 --- a/Engine/Source/Editor/GraphEditor/Private/KismetNodes/SGraphNodeK2CreateDelegate.cpp +++ b/Engine/Source/Editor/GraphEditor/Private/KismetNodes/SGraphNodeK2CreateDelegate.cpp @@ -56,7 +56,7 @@ FText SGraphNodeK2CreateDelegate::GetCurrentFunctionDescription() const if(!FunctionSignature || !ScopeClass) { - return NSLOCTEXT("GraphNodeK2Create", "NoneLabel", "None"); + return NSLOCTEXT("GraphNodeK2Create", "NoneLabel", ""); } if (const auto Func = FindField(ScopeClass, Node->GetFunctionName())) @@ -69,7 +69,7 @@ FText SGraphNodeK2CreateDelegate::GetCurrentFunctionDescription() const return FText::Format(NSLOCTEXT("GraphNodeK2Create", "ErrorLabelFmt", "Error? {0}"), FText::FromName(Node->GetFunctionName())); } - return NSLOCTEXT("GraphNodeK2Create", "SelectFunctionLabel", "Select Function"); + return NSLOCTEXT("GraphNodeK2Create", "SelectFunctionLabel", "Select Function..."); } TSharedRef SGraphNodeK2CreateDelegate::HandleGenerateRowFunction(TSharedPtr FunctionItemData, const TSharedRef& OwnerTable) @@ -109,6 +109,7 @@ void SGraphNodeK2CreateDelegate::CreateBelowWidgetControls(TSharedPtr It(ScopeClass); It; ++It) { UFunction* Func = *It; @@ -122,6 +123,14 @@ void SGraphNodeK2CreateDelegate::CreateBelowWidgetControls(TSharedPtr EmptyEntry = MakeShareable(new FFunctionItemData()); + EmptyEntry->Description = NSLOCTEXT("GraphNodeK2Create", "EmptyFunctionLabel", "[NONE]").ToString(); + FunctionDataItems.Add(EmptyEntry); + } + TSharedRef SelectFunctionWidgetRef = SNew(SComboButton) .Method(EPopupMethod::UseCurrentWindow) .ButtonContent() diff --git a/Engine/Source/Editor/KismetCompiler/Private/AnimBlueprintCompiler.cpp b/Engine/Source/Editor/KismetCompiler/Private/AnimBlueprintCompiler.cpp index 7709f4faee01..eac3b47bfdc4 100644 --- a/Engine/Source/Editor/KismetCompiler/Private/AnimBlueprintCompiler.cpp +++ b/Engine/Source/Editor/KismetCompiler/Private/AnimBlueprintCompiler.cpp @@ -121,12 +121,6 @@ UK2Node_CallFunction* FAnimBlueprintCompiler::SpawnCallAnimInstanceFunction(UEdG void FAnimBlueprintCompiler::CreateEvaluationHandler(UAnimGraphNode_Base* VisualAnimNode, FEvaluationHandlerRecord& Record) { - if(Record.OnlyUsesCopyRecords()) - { - // simple property copies don't require wiring up to a custom event - return; - } - // Shouldn't create a handler if there is nothing to work with check(Record.ServicedProperties.Num() > 0); check(Record.NodeVariableProperty != NULL); @@ -1208,6 +1202,9 @@ void FAnimBlueprintCompiler::MergeUbergraphPagesIn(UEdGraph* Ubergraph) } } + // Make sure we expand any split pins here before we process animation nodes. + ExpansionStep(ConsolidatedEventGraph, false); + // Compile the animation graph ProcessAllAnimationNodes(); } @@ -1365,7 +1362,9 @@ void FAnimBlueprintCompiler::PostCompile() const FAnimNodeSinglePropertyHandler& Handler = EvaluationHandler.ServicedProperties.CreateConstIterator()->Value; UAnimGraphNode_Base* Node = CastChecked(Handler.ArrayPins.Num() > 0 ? Handler.ArrayPins[0]->GetOwningNode() : Handler.SinglePin->GetOwningNode()); UAnimGraphNode_Base* TrueNode = MessageLog.FindSourceObjectTypeChecked(Node); - TrueNode->BlueprintUsage = EvaluationHandler.HandlerFunctionName != NAME_None ? EBlueprintUsage::UsesBlueprint : EBlueprintUsage::DoesNotUseBlueprint; + + FExposedValueHandler* HandlerPtr = EvaluationHandler.EvaluationHandlerProperty->ContainerPtrToValuePtr(EvaluationHandler.NodeVariableProperty->ContainerPtrToValuePtr(DefaultAnimInstance)); + TrueNode->BlueprintUsage = HandlerPtr->BoundFunction != NAME_None ? EBlueprintUsage::UsesBlueprint : EBlueprintUsage::DoesNotUseBlueprint; if(TrueNode->BlueprintUsage == EBlueprintUsage::UsesBlueprint && DefaultAnimInstance->bWarnAboutBlueprintUsage) { @@ -1897,26 +1896,56 @@ void FAnimBlueprintCompiler::FEvaluationHandlerRecord::PatchFunctionNameAndCopyR // we dont support copying *from* array properties at the moment if (SimpleCopyPropertySource && !SimpleCopyPropertySource->IsA()) { + // are we copying to an array element (or more than one)? if (AnimNodeSinglePropertyHandler.ArrayPins.Num() > 0) { UArrayProperty* SimpleCopyPropertyDest = CastChecked(NodeVariableProperty->Struct->FindPropertyByName(PropertyIt.Key())); - if(SimpleCopyPropertySource->GetSize() != SimpleCopyPropertyDest->Inner->GetSize()) - { - bOnlyUsesCopyRecords = false; - break; - } - for (TMap::TConstIterator ArrayIt(AnimNodeSinglePropertyHandler.ArrayPins); ArrayIt; ++ArrayIt) + if (AnimNodeSinglePropertyHandler.SubStructPropertyName != NAME_None) { - FExposedValueCopyRecord CopyRecord; - CopyRecord.DestProperty = SimpleCopyPropertyDest; - CopyRecord.DestArrayIndex = ArrayIt.Key(); - CopyRecord.SourcePropertyName = AnimNodeSinglePropertyHandler.SimpleCopyPropertyName; - CopyRecord.SourceSubPropertyName = NAME_None; - CopyRecord.SourceArrayIndex = 0; - CopyRecord.Size = SimpleCopyPropertyDest->Inner->GetSize(); - CopyRecord.PostCopyOperation = AnimNodeSinglePropertyHandler.Operation; - HandlerPtr->CopyRecords.Add(CopyRecord); + UStructProperty* SourceStructProperty = CastChecked(SimpleCopyPropertySource); + UProperty* SourceSubProperty = SourceStructProperty->Struct->FindPropertyByName(AnimNodeSinglePropertyHandler.SubStructPropertyName); + if (SourceSubProperty == nullptr || SourceSubProperty->GetSize() != SimpleCopyPropertyDest->Inner->GetSize()) + { + bOnlyUsesCopyRecords = false; + break; + } + + for (TMap::TConstIterator ArrayIt(AnimNodeSinglePropertyHandler.ArrayPins); ArrayIt; ++ArrayIt) + { + // Single sub-struct variable get->array set + FExposedValueCopyRecord CopyRecord; + CopyRecord.DestProperty = SimpleCopyPropertyDest; + CopyRecord.DestArrayIndex = ArrayIt.Key(); + CopyRecord.SourcePropertyName = AnimNodeSinglePropertyHandler.SimpleCopyPropertyName; + CopyRecord.SourceSubPropertyName = AnimNodeSinglePropertyHandler.SubStructPropertyName; + CopyRecord.SourceArrayIndex = 0; + CopyRecord.Size = SimpleCopyPropertyDest->Inner->GetSize(); + CopyRecord.PostCopyOperation = AnimNodeSinglePropertyHandler.Operation; + HandlerPtr->CopyRecords.Add(CopyRecord); + } + } + else + { + if (SimpleCopyPropertySource->GetSize() != SimpleCopyPropertyDest->Inner->GetSize()) + { + bOnlyUsesCopyRecords = false; + break; + } + + for (TMap::TConstIterator ArrayIt(AnimNodeSinglePropertyHandler.ArrayPins); ArrayIt; ++ArrayIt) + { + // Single variable get->array set + FExposedValueCopyRecord CopyRecord; + CopyRecord.DestProperty = SimpleCopyPropertyDest; + CopyRecord.DestArrayIndex = ArrayIt.Key(); + CopyRecord.SourcePropertyName = AnimNodeSinglePropertyHandler.SimpleCopyPropertyName; + CopyRecord.SourceSubPropertyName = NAME_None; + CopyRecord.SourceArrayIndex = 0; + CopyRecord.Size = SimpleCopyPropertyDest->Inner->GetSize(); + CopyRecord.PostCopyOperation = AnimNodeSinglePropertyHandler.Operation; + HandlerPtr->CopyRecords.Add(CopyRecord); + } } } else @@ -1938,7 +1967,7 @@ void FAnimBlueprintCompiler::FEvaluationHandlerRecord::PatchFunctionNameAndCopyR break; } - // Local sub-struct variable get + // Single sub-struct variable get->single variable set FExposedValueCopyRecord CopyRecord; CopyRecord.DestProperty = SimpleCopyPropertyDest; CopyRecord.DestArrayIndex = 0; @@ -1957,7 +1986,7 @@ void FAnimBlueprintCompiler::FEvaluationHandlerRecord::PatchFunctionNameAndCopyR break; } - // Local variable get + // Single variable get->single variable set FExposedValueCopyRecord CopyRecord; CopyRecord.DestProperty = SimpleCopyPropertyDest; CopyRecord.DestArrayIndex = 0; diff --git a/Engine/Source/Editor/LandscapeEditor/Private/LandscapeEdModeSplineTools.cpp b/Engine/Source/Editor/LandscapeEditor/Private/LandscapeEdModeSplineTools.cpp index 2e4506758410..52eda9eeb69f 100644 --- a/Engine/Source/Editor/LandscapeEditor/Private/LandscapeEdModeSplineTools.cpp +++ b/Engine/Source/Editor/LandscapeEditor/Private/LandscapeEdModeSplineTools.cpp @@ -378,6 +378,11 @@ public: AddSegment(ControlPoint, NewControlPoint, bAutoRotateOnJoin, true); } } + else + { + // required to make control point visible + NewControlPoint->UpdateSplinePoints(); + } ClearSelection(); SelectControlPoint(NewControlPoint); diff --git a/Engine/Source/Editor/LandscapeEditor/Private/LandscapeSplineImportExport.cpp b/Engine/Source/Editor/LandscapeEditor/Private/LandscapeSplineImportExport.cpp index 4e968548c5d6..3df20e96f288 100644 --- a/Engine/Source/Editor/LandscapeEditor/Private/LandscapeSplineImportExport.cpp +++ b/Engine/Source/Editor/LandscapeEditor/Private/LandscapeSplineImportExport.cpp @@ -31,7 +31,7 @@ void FLandscapeSplineTextObjectFactory::ProcessConstructedObject(UObject* Create CreatedObject->PostEditImport(); } -bool FLandscapeSplineTextObjectFactory::CanCreateClass(UClass* ObjectClass) const +bool FLandscapeSplineTextObjectFactory::CanCreateClass(UClass* ObjectClass, bool& bOmitSubObjs) const { if (ObjectClass == ULandscapeSplineControlPoint::StaticClass() || ObjectClass == ULandscapeSplineSegment::StaticClass()) diff --git a/Engine/Source/Editor/LandscapeEditor/Private/LandscapeSplineImportExport.h b/Engine/Source/Editor/LandscapeEditor/Private/LandscapeSplineImportExport.h index 16bb3656cf35..3907179b5b44 100644 --- a/Engine/Source/Editor/LandscapeEditor/Private/LandscapeSplineImportExport.h +++ b/Engine/Source/Editor/LandscapeEditor/Private/LandscapeSplineImportExport.h @@ -15,5 +15,5 @@ protected: TArray OutObjects; virtual void ProcessConstructedObject(UObject* CreatedObject) override; - virtual bool CanCreateClass(UClass* ObjectClass) const override; + virtual bool CanCreateClass(UClass* ObjectClass, bool& bOmitSubObjs) const override; }; diff --git a/Engine/Source/Editor/LevelEditor/Private/LevelEditorActions.cpp b/Engine/Source/Editor/LevelEditor/Private/LevelEditorActions.cpp index f3b8b7f17a20..9696ab195994 100644 --- a/Engine/Source/Editor/LevelEditor/Private/LevelEditorActions.cpp +++ b/Engine/Source/Editor/LevelEditor/Private/LevelEditorActions.cpp @@ -227,15 +227,19 @@ void FLevelEditorActionCallbacks::OpenRecentFile( int32 RecentFileIndex ) FMainMRUFavoritesList* RecentsAndFavorites = MainFrameModule.GetMRUFavoritesList(); // Save the name of the file we are attempting to load as VerifyFile/AskSaveChanges might rearrange the MRU list on us - const FString NewFilename = RecentsAndFavorites->GetMRUItem( RecentFileIndex ); + const FString NewPackageName = RecentsAndFavorites->GetMRUItem( RecentFileIndex ); if( RecentsAndFavorites->VerifyMRUFile( RecentFileIndex ) ) { // Prompt the user to save any outstanding changes. if( FEditorFileUtils::SaveDirtyPackages(true, true, false) ) { - // Load the requested level. - FEditorFileUtils::LoadMap( NewFilename ); + FString NewFilename; + if (FPackageName::TryConvertLongPackageNameToFilename(NewPackageName, NewFilename, FPackageName::GetMapPackageExtension())) + { + // Load the requested level. + FEditorFileUtils::LoadMap(NewFilename); + } } else { @@ -250,18 +254,22 @@ void FLevelEditorActionCallbacks::OpenFavoriteFile( int32 FavoriteFileIndex ) IMainFrameModule& MainFrameModule = FModuleManager::LoadModuleChecked( "MainFrame" ); FMainMRUFavoritesList* MRUFavoritesList = MainFrameModule.GetMRUFavoritesList(); - const FString FileName = MRUFavoritesList->GetFavoritesItem( FavoriteFileIndex ); + const FString PackageName = MRUFavoritesList->GetFavoritesItem( FavoriteFileIndex ); if( MRUFavoritesList->VerifyFavoritesFile( FavoriteFileIndex ) ) { // Prompt the user to save any outstanding changes if( FEditorFileUtils::SaveDirtyPackages(true, true, false) ) { - // Load the requested level. - FEditorFileUtils::LoadMap( FileName ); + FString FileName; + if (FPackageName::TryConvertLongPackageNameToFilename(PackageName, FileName, FPackageName::GetMapPackageExtension())) + { + // Load the requested level. + FEditorFileUtils::LoadMap(FileName); + } // Move the item to the head of the list - MRUFavoritesList->MoveFavoritesItemToHead( FileName ); + MRUFavoritesList->MoveFavoritesItemToHead(PackageName); } else { @@ -277,21 +285,23 @@ void FLevelEditorActionCallbacks::ToggleFavorite() FMainMRUFavoritesList* MRUFavoritesList = MainFrameModule.GetMRUFavoritesList(); check( MRUFavoritesList ); + const FString PackageName = GetWorld()->GetOutermost()->GetName(); + FString MapFileName; - const bool bMapFileExists = FPackageName::DoesPackageExist(GetWorld()->GetOutermost()->GetName(), NULL, &MapFileName); + const bool bMapFileExists = FPackageName::DoesPackageExist(PackageName, NULL, &MapFileName); // If the user clicked the toggle favorites button, the map file should exist, but double check to be safe. if ( bMapFileExists ) { // If the map was already favorited, remove it from the favorites - if ( MRUFavoritesList->ContainsFavoritesItem( MapFileName ) ) + if ( MRUFavoritesList->ContainsFavoritesItem(PackageName) ) { - MRUFavoritesList->RemoveFavoritesItem( MapFileName ); + MRUFavoritesList->RemoveFavoritesItem(PackageName); } // If the map was not already favorited, add it to the favorites else { - MRUFavoritesList->AddFavoritesItem( MapFileName ); + MRUFavoritesList->AddFavoritesItem(PackageName); } } } @@ -302,13 +312,13 @@ void FLevelEditorActionCallbacks::RemoveFavorite( int32 FavoriteFileIndex ) IMainFrameModule& MainFrameModule = FModuleManager::LoadModuleChecked( "MainFrame" ); FMainMRUFavoritesList* MRUFavoritesList = MainFrameModule.GetMRUFavoritesList(); - const FString FileName = MRUFavoritesList->GetFavoritesItem( FavoriteFileIndex ); + const FString PackageName = MRUFavoritesList->GetFavoritesItem( FavoriteFileIndex ); if( MRUFavoritesList->VerifyFavoritesFile( FavoriteFileIndex ) ) { - if ( MRUFavoritesList->ContainsFavoritesItem( FileName ) ) + if ( MRUFavoritesList->ContainsFavoritesItem(PackageName) ) { - MRUFavoritesList->RemoveFavoritesItem( FileName ); + MRUFavoritesList->RemoveFavoritesItem(PackageName); } } } @@ -333,18 +343,17 @@ bool FLevelEditorActionCallbacks::ToggleFavorite_IsChecked() { bool bIsChecked = false; + const FString PackageName = GetWorld()->GetOutermost()->GetName(); + FString FileName; - const bool bMapFileExists = FPackageName::DoesPackageExist(GetWorld()->GetOutermost()->GetName(), NULL, &FileName); + const bool bMapFileExists = FPackageName::DoesPackageExist(PackageName, NULL, &FileName); // If the map exists, determine its state based on whether the map is already favorited or not if ( bMapFileExists ) { IMainFrameModule& MainFrameModule = FModuleManager::LoadModuleChecked( "MainFrame" ); - const FString CleanedName = FPaths::ConvertRelativePathToFull(FileName); - const bool bCleanAlreadyFavorited = MainFrameModule.GetMRUFavoritesList()->ContainsFavoritesItem( CleanedName ); - const bool bAlreadyFavorited = bCleanAlreadyFavorited || MainFrameModule.GetMRUFavoritesList()->ContainsFavoritesItem( FileName ); - bIsChecked = bAlreadyFavorited; + bIsChecked = MainFrameModule.GetMRUFavoritesList()->ContainsFavoritesItem(PackageName); } return bIsChecked; diff --git a/Engine/Source/Editor/LevelEditor/Private/LevelEditorMenu.cpp b/Engine/Source/Editor/LevelEditor/Private/LevelEditorMenu.cpp index 7c1d90ff5130..083c23efdfbc 100644 --- a/Engine/Source/Editor/LevelEditor/Private/LevelEditorMenu.cpp +++ b/Engine/Source/Editor/LevelEditor/Private/LevelEditorMenu.cpp @@ -279,7 +279,7 @@ TSharedRef< SWidget > FLevelEditorMenu::MakeLevelEditorMenu( const TSharedPtr FLevelEditorToolBar::GenerateCinematicsMenuContent( TShare MenuBuilder.EndSection(); UWorld* World = LevelEditorWeakPtr.Pin()->GetWorld(); - const bool bHasAnyMatineeActors = !!TActorIterator(World) || !!TActorIterator(World); + const bool bHasAnyCinematicsActors = !!TActorIterator(World) || !!TActorIterator(World); - //Add a heading to separate the existing matinees from the 'Add New Matinee Actor' button - MenuBuilder.BeginSection("LevelEditorExistingMatinee", LOCTEXT( "MatineeMenuCombo_ExistingHeading", "Edit Existing Matinee" ) ); + //Add a heading to separate the existing cinematics from the 'Add New Cinematic Actor' button + MenuBuilder.BeginSection("LevelEditorExistingCinematic", LOCTEXT( "CinematicMenuCombo_ExistingHeading", "Edit Existing Cinematic" ) ); { - if( bHasAnyMatineeActors ) + if( bHasAnyCinematicsActors ) { MenuBuilder.AddWidget(MiniSceneOutliner, FText::GetEmpty(), true); } diff --git a/Engine/Source/Editor/LevelEditor/Private/LevelViewportLayout.cpp b/Engine/Source/Editor/LevelEditor/Private/LevelViewportLayout.cpp index 33e0dc0ff989..1b8ce48e0b04 100644 --- a/Engine/Source/Editor/LevelEditor/Private/LevelViewportLayout.cpp +++ b/Engine/Source/Editor/LevelEditor/Private/LevelViewportLayout.cpp @@ -245,7 +245,8 @@ void FLevelViewportLayout::SaveCommonLayoutString( const FString& SpecificLayout // Save all our data using the additional layout config for (auto& Pair : Viewports) { - FString ConfigName = SpecificLayoutString + Pair.Key.ToString(); + // The Viewports map is keyed on the full config name, so no need to prepend the SpecificLayoutString + FString ConfigName = Pair.Key.ToString(); Pair.Value->SaveConfig(ConfigName); diff --git a/Engine/Source/Editor/LevelEditor/Public/LevelViewportLayout.h b/Engine/Source/Editor/LevelEditor/Public/LevelViewportLayout.h index 8bdc9e69c238..53da7691591e 100644 --- a/Engine/Source/Editor/LevelEditor/Public/LevelViewportLayout.h +++ b/Engine/Source/Editor/LevelEditor/Public/LevelViewportLayout.h @@ -258,7 +258,7 @@ protected: /** Curve for animating from a "restored" state to a maximized state */ FCurveSequence MaximizeAnimation; - /** List of all of the viewports in this layout */ + /** List of all of the viewports in this layout, keyed on their config key */ TMap< FName, TSharedPtr< IViewportLayoutEntity > > Viewports; /** The parent tab where this layout resides */ diff --git a/Engine/Source/Editor/MovieSceneTools/Private/CurveKeyAreas/FloatCurveKeyArea.cpp b/Engine/Source/Editor/MovieSceneTools/Private/CurveKeyAreas/FloatCurveKeyArea.cpp index b7bbf0669b1f..7aaef62e6830 100644 --- a/Engine/Source/Editor/MovieSceneTools/Private/CurveKeyAreas/FloatCurveKeyArea.cpp +++ b/Engine/Source/Editor/MovieSceneTools/Private/CurveKeyAreas/FloatCurveKeyArea.cpp @@ -58,6 +58,11 @@ TArray FFloatCurveKeyArea::AddKeyUnique(float Time, EMovieSceneKeyIn CurrentKey.LeaveTangentWeight = KeyToCopy.LeaveTangentWeight; } } + else if ( IntermediateValue.IsSet() ) + { + float Value = IntermediateValue.GetValue(); + Curve->UpdateOrAddKey(Time,Value); + } return AddedKeyHandles; } diff --git a/Engine/Source/Editor/MovieSceneTools/Private/CurveKeyAreas/IntegralKeyArea.cpp b/Engine/Source/Editor/MovieSceneTools/Private/CurveKeyAreas/IntegralKeyArea.cpp index 195c44caf5d0..7a70b4e2725c 100644 --- a/Engine/Source/Editor/MovieSceneTools/Private/CurveKeyAreas/IntegralKeyArea.cpp +++ b/Engine/Source/Editor/MovieSceneTools/Private/CurveKeyAreas/IntegralKeyArea.cpp @@ -27,6 +27,10 @@ TArray FIntegralCurveKeyAreaBase::AddKeyUnique(float Time, EMovieSce EvaluateAndAddKey(Time, TimeToCopyFrom, CurrentKey); AddedKeyHandles.Add(CurrentKey); } + else + { + SetKeyValue(Time); + } return AddedKeyHandles; } diff --git a/Engine/Source/Editor/MovieSceneTools/Public/IntegralKeyArea.h b/Engine/Source/Editor/MovieSceneTools/Public/IntegralKeyArea.h index 2d49010145a1..dba6392ffb71 100644 --- a/Engine/Source/Editor/MovieSceneTools/Public/IntegralKeyArea.h +++ b/Engine/Source/Editor/MovieSceneTools/Public/IntegralKeyArea.h @@ -45,6 +45,7 @@ public: protected: virtual void EvaluateAndAddKey(float Time, float TimeToCopyFrom, FKeyHandle& CurrentKey) = 0; + virtual void SetKeyValue(float Time) = 0; protected: @@ -158,6 +159,16 @@ protected: Curve.AddKey(Time, Value, CurrentKey); } + virtual void SetKeyValue(float Time) override + { + if (IntermediateValue.IsSet()) + { + int32 Value = IntermediateValue.GetValue(); + + Curve.UpdateOrAddKey(Time, Value); + } + } + protected: TOptional IntermediateValue; diff --git a/Engine/Source/Editor/Persona/Private/SAnimNotifyPanel.cpp b/Engine/Source/Editor/Persona/Private/SAnimNotifyPanel.cpp index b0f8ac9592fb..c9da9b5817fa 100644 --- a/Engine/Source/Editor/Persona/Private/SAnimNotifyPanel.cpp +++ b/Engine/Source/Editor/Persona/Private/SAnimNotifyPanel.cpp @@ -2377,6 +2377,11 @@ void SAnimNotifyTrack::FillNewNotifyMenu(FMenuBuilder& MenuBuilder, bool bIsRepl { for(UClass* Class : NativeNotifyClasses) { + if (Class->HasAllClassFlags(CLASS_Abstract)) + { + continue; // skip abstract classes + } + const FText LabelText = Class->GetDisplayNameText(); const FString Label = LabelText.ToString(); @@ -4785,7 +4790,7 @@ void SAnimNotifyPanel::OnGetNativeNotifyData(TArray& OutClasses, UClass { UClass* Class = *It; - if(Class->IsChildOf(NotifyOutermost) && Class->HasAllClassFlags(CLASS_Native) && !Class->HasAllClassFlags(CLASS_Abstract) && !Class->IsInBlueprint()) + if(Class->IsChildOf(NotifyOutermost) && Class->HasAllClassFlags(CLASS_Native) && !Class->IsInBlueprint()) { OutClasses.Add(Class); // Form class name to search later diff --git a/Engine/Source/Editor/Persona/Private/SSkeletonTree.cpp b/Engine/Source/Editor/Persona/Private/SSkeletonTree.cpp index c52679cc92ee..6e14157bc474 100644 --- a/Engine/Source/Editor/Persona/Private/SSkeletonTree.cpp +++ b/Engine/Source/Editor/Persona/Private/SSkeletonTree.cpp @@ -58,7 +58,7 @@ public: }; private: - virtual bool CanCreateClass(UClass* ObjectClass) const { return true; } + virtual bool CanCreateClass(UClass* ObjectClass, bool& bOmitSubObjs) const override { return true; } virtual void ProcessConstructedObject( UObject* CreatedObject ) { diff --git a/Engine/Source/Editor/PixelInspector/Private/PixelInspector.cpp b/Engine/Source/Editor/PixelInspector/Private/PixelInspector.cpp index f6e8394ea95d..7b1c849369d0 100644 --- a/Engine/Source/Editor/PixelInspector/Private/PixelInspector.cpp +++ b/Engine/Source/Editor/PixelInspector/Private/PixelInspector.cpp @@ -2,6 +2,7 @@ #include "PixelInspectorPrivatePCH.h" #include "PixelInspector.h" +#include "PixelInspectorStyle.h" #include "Editor.h" #include "EditorModeManager.h" @@ -9,6 +10,7 @@ #include "IDetailsView.h" #include "PixelInspectorDetailsCustomization.h" #include "LevelEditor.h" +#include "SNumericEntryBox.h" #define PIXEL_INSPECTOR_REQUEST_TIMEOUT 10 #define MINIMUM_TICK_BETWEEN_CREATE_REQUEST 10 @@ -19,10 +21,15 @@ namespace PixelInspector SPixelInspector::SPixelInspector() { DisplayResult = nullptr; + LastViewportInspectionPosition = FIntPoint(-1, -1); + LastViewportId = 0; + LastViewportInspectionSize = FIntPoint(1, 1); bIsPixelInspectorEnable = false; Buffer_FinalColor_RGB8[0] = nullptr; Buffer_FinalColor_RGB8[1] = nullptr; + Buffer_SceneColor_Float[0] = nullptr; + Buffer_SceneColor_Float[1] = nullptr; Buffer_HDR_Float[0] = nullptr; Buffer_HDR_Float[1] = nullptr; Buffer_Depth_Float[0] = nullptr; @@ -57,7 +64,7 @@ namespace PixelInspector void SPixelInspector::OnApplicationPreInputKeyDownListener(const FKeyEvent& InKeyEvent) { - if (InKeyEvent.GetKey() == EKeys::Escape && bIsPixelInspectorEnable) + if (InKeyEvent.GetKey() == EKeys::Escape && (bIsPixelInspectorEnable)) { // disable the pixel inspector bIsPixelInspectorEnable = false; @@ -137,6 +144,16 @@ namespace PixelInspector BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION void SPixelInspector::Construct(const FArguments& InArgs) { + //Set the LastViewportId to point on the active viewport + FViewport *ActiveViewport = GEditor->GetActiveViewport(); + for (FEditorViewportClient *EditorViewport : GEditor->AllViewportClients) + { + if (ActiveViewport == EditorViewport->Viewport && EditorViewport->ViewState.GetReference() != nullptr) + { + LastViewportId = EditorViewport->ViewState.GetReference()->GetViewKey(); + } + } + TSharedPtr InspectorBox; //Create the PixelInspector UI TSharedPtr VerticalBox = SNew(SVerticalBox) @@ -145,23 +162,114 @@ namespace PixelInspector [ SNew(SHorizontalBox) + SHorizontalBox::Slot() + .Padding(0.0f, 3.0f, 0.0f, 3.0f) .AutoWidth() [ - SNew(SCheckBox) + SNew(SButton) .HAlign(HAlign_Center) - .OnCheckStateChanged(this, &SPixelInspector::HandleTogglePixelInspectorEnable) - .IsChecked(this, &SPixelInspector::IsPixelInspectorEnable) + .ToolTipText(this, &SPixelInspector::GetPixelInspectorEnableButtonTooltipText) + .OnClicked(this, &SPixelInspector::HandleTogglePixelInspectorEnableButton) + [ + SNew(SImage) + .Image(this, &SPixelInspector::GetPixelInspectorEnableButtonBrush) + ] ] + SHorizontalBox::Slot() - .FillWidth(1.0f) - .Padding(0.0f, 3.0f, 6.0f, 3.0f) + .Padding(6.0f, 3.0f, 0.0f, 3.0f) .VAlign(VAlign_Center) + .AutoWidth() [ SNew(STextBlock) - .Text(LOCTEXT("PixelInspector_EnableCheckbox", "Enable Pixel Inspector")) + .MinDesiredWidth(75) + .Text(this, &SPixelInspector::GetPixelInspectorEnableButtonText) ] ] + SVerticalBox::Slot() + .AutoHeight() + [ + SNew(SHorizontalBox) + + SHorizontalBox::Slot() + .AutoWidth() + .Padding(0.0f, 3.0f, 16.0f, 3.0f) + .VAlign(VAlign_Center) + [ + SNew(STextBlock) + .MinDesiredWidth(75) + .Text(LOCTEXT("PixelInspector_ViewportIdValue", "Viewport Id")) + ] + + SHorizontalBox::Slot() + .AutoWidth() + .Padding(0.0f, 3.0f, 0.0f, 3.0f) + [ + SNew(SNumericEntryBox) + .IsEnabled(false) + .MinDesiredValueWidth(75) + .Value(this, &SPixelInspector::GetCurrentViewportId) + ] + ] + + SVerticalBox::Slot() + .AutoHeight() + [ + SNew(SHorizontalBox) + + SHorizontalBox::Slot() + .AutoWidth() + .Padding(0.0f, 3.0f, 16.0f, 3.0f) + .VAlign(VAlign_Center) + [ + SNew(STextBlock) + .MinDesiredWidth(75) + .Text(LOCTEXT("PixelInspector_ViewportCoordinate", "Coordinate")) + .ToolTipText(LOCTEXT("PixelInspector_ViewportCoordinateTooltip", "Coordinate relative to the inspected viewport")) + ] + + SHorizontalBox::Slot() + .AutoWidth() + .Padding(0.0f, 3.0f, 8.0f, 3.0f) + [ + SNew(SNumericEntryBox) + .IsEnabled(this, &SPixelInspector::IsPixelInspectorEnable) + .Value(this, &SPixelInspector::GetCurrentCoordinateX) + .OnValueChanged(this, &SPixelInspector::SetCurrentCoordinateX) + .OnValueCommitted(this, &SPixelInspector::SetCurrentCoordinateXCommit) + .AllowSpin(true) + .MinValue(0) + .MaxSliderValue(this, &SPixelInspector::GetMaxCoordinateX) + .MinDesiredValueWidth(75) + .Label() + [ + SNew(SBox) + .VAlign(VAlign_Center) + [ + SNew(STextBlock) + .Text(LOCTEXT("CoordinateViewport_X", "X")) + ] + ] + ] + + SHorizontalBox::Slot() + .Padding(0.0f, 3.0f, 8.0f, 3.0f) + .AutoWidth() + [ + SNew(SNumericEntryBox) + .IsEnabled(this, &SPixelInspector::IsPixelInspectorEnable) + .Value(this, &SPixelInspector::GetCurrentCoordinateY) + .OnValueChanged(this, &SPixelInspector::SetCurrentCoordinateY) + .OnValueCommitted(this, &SPixelInspector::SetCurrentCoordinateYCommit) + .AllowSpin(true) + .MinValue(0) + .MaxSliderValue(this, &SPixelInspector::GetMaxCoordinateY) + .MinDesiredValueWidth(75) + .Label() + [ + SNew(SBox) + .VAlign(VAlign_Center) + [ + SNew(STextBlock) + .Text(LOCTEXT("CoordinateViewport_Y", "Y")) + ] + ] + ] + ] + + SVerticalBox::Slot() + .Padding(0.0f, 12.0f, 0.0f, 3.0f) .FillHeight(1.0f) [ SAssignNew(InspectorBox, SBox) @@ -169,7 +277,13 @@ namespace PixelInspector FPropertyEditorModule& PropertyEditorModule = FModuleManager::GetModuleChecked("PropertyEditor"); FDetailsViewArgs DetailsViewArgs; - DetailsViewArgs.bAllowSearch = true; + DetailsViewArgs.bAllowSearch = false; + DetailsViewArgs.bLockable = false; + DetailsViewArgs.bShowActorLabel = false; + DetailsViewArgs.bShowOptions = false; + DetailsViewArgs.bUpdatesFromSelection = false; + DetailsViewArgs.bHideSelectionTip = true; + DetailsViewArgs.bSearchInitialKeyFocus = false; DetailsViewArgs.NameAreaSettings = FDetailsViewArgs::HideNameArea; DisplayDetailsView = PropertyEditorModule.CreateDetailView(DetailsViewArgs); InspectorBox->SetContent(DisplayDetailsView->AsShared()); @@ -191,35 +305,129 @@ namespace PixelInspector } + END_SLATE_FUNCTION_BUILD_OPTIMIZATION + + FReply SPixelInspector::HandleTogglePixelInspectorEnableButton() + { + bIsPixelInspectorEnable = !bIsPixelInspectorEnable; + if (bIsPixelInspectorEnable) + { + if (LastViewportInspectionPosition == FIntPoint(-1, -1)) + { + //Let the system inspect a pixel so the user can see the UI appear + LastViewportInspectionPosition = FIntPoint(0, 0); + } + //Make sure the viewport is switch to realtime + SetCurrentViewportInRealtime(); + } + return FReply::Handled(); + } + + FText SPixelInspector::GetPixelInspectorEnableButtonText() const + { + if (bIsPixelInspectorEnable) + { + return LOCTEXT("PixelInspector_EnableCheckbox_Inspecting", "Inspecting"); + } + + return LOCTEXT("PixelInspectorMouseHover_EnableCheckbox", "Start Pixel Inspector"); + } + + FText SPixelInspector::GetPixelInspectorEnableButtonTooltipText() const + { + if (bIsPixelInspectorEnable) + { + return LOCTEXT("PixelInspector_EnableCheckbox_ESC", "Inspecting (ESC to stop)"); + } + + return LOCTEXT("PixelInspectorMouseHover_EnableCheckbox", "Start Pixel Inspection"); + } + + const FSlateBrush* SPixelInspector::GetPixelInspectorEnableButtonBrush() const + { + return bIsPixelInspectorEnable ? FPixelInspectorStyle::Get()->GetBrush("PixelInspector.Enabled") : FPixelInspectorStyle::Get()->GetBrush("PixelInspector.Disabled"); + } + + void SPixelInspector::SetCurrentCoordinateXCommit(int32 NewValue, ETextCommit::Type) + { + ReleaseAllRequests(); + SetCurrentCoordinateX(NewValue); + } + + void SPixelInspector::SetCurrentCoordinateX(int32 NewValue) + { + LastViewportInspectionPosition.X = NewValue; + } + + void SPixelInspector::SetCurrentCoordinateYCommit(int32 NewValue, ETextCommit::Type) + { + ReleaseAllRequests(); + SetCurrentCoordinateY(NewValue); + } + void SPixelInspector::SetCurrentCoordinateY(int32 NewValue) + { + LastViewportInspectionPosition.Y = NewValue; + } + + void SPixelInspector::SetCurrentCoordinate(FIntPoint NewCoordinate, bool ReleaseAllRequest) + { + if (ReleaseAllRequest) + { + ReleaseAllRequests(); + } + LastViewportInspectionPosition.X = NewCoordinate.X; + LastViewportInspectionPosition.Y = NewCoordinate.Y; + } + + TOptional SPixelInspector::GetMaxCoordinateX() const + { + return LastViewportInspectionSize.X - 1; + } + + TOptional SPixelInspector::GetMaxCoordinateY() const + { + return LastViewportInspectionSize.Y - 1; + } + + void SPixelInspector::SetCurrentViewportInRealtime() + { + //Force viewport refresh + for (FEditorViewportClient *EditorViewport : GEditor->AllViewportClients) + { + if (EditorViewport->ViewState.GetReference() != nullptr) + { + if (EditorViewport->ViewState.GetReference()->GetViewKey() == LastViewportId) + { + if (!EditorViewport->IsRealtime()) + { + EditorViewport->SetRealtime(true); + } + } + } + } + } void SPixelInspector::Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime) { SCompoundWidget::Tick(AllottedGeometry, InCurrentTime, InDeltaTime); -/* if (!GIsRequestingExit) - { - //Read back the buffer that are ready - ReadBackRequestData(); - }*/ TickSinceLastCreateRequest++; } - - END_SLATE_FUNCTION_BUILD_OPTIMIZATION - - ECheckBoxState SPixelInspector::IsPixelInspectorEnable() const - { - return bIsPixelInspectorEnable ? ECheckBoxState::Checked : ECheckBoxState::Unchecked; - } - - void SPixelInspector::HandleTogglePixelInspectorEnable(ECheckBoxState CheckType) - { - bIsPixelInspectorEnable = (CheckType == ECheckBoxState::Checked); - } - + void SPixelInspector::CreatePixelInspectorRequest(FIntPoint ScreenPosition, int32 viewportUniqueId, FSceneInterface *SceneInterface) { if (TickSinceLastCreateRequest < MINIMUM_TICK_BETWEEN_CREATE_REQUEST) return; + if (ScreenPosition == FIntPoint(-1, -1)) + { + return; + } + //Make sure we dont get value outside the viewport size + if ( ScreenPosition.X >= LastViewportInspectionSize.X || ScreenPosition.Y >= LastViewportInspectionSize.Y ) + { + return; + } + TickSinceLastCreateRequest = 0; // We need to know if the GBuffer is in low, default or high precision buffer const auto CVarGBufferFormat = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.GBufferFormat")); @@ -253,6 +461,12 @@ namespace PixelInspector Buffer_FinalColor_RGB8[BufferIndex]->RemoveFromRoot(); Buffer_FinalColor_RGB8[BufferIndex] = nullptr; } + if (Buffer_SceneColor_Float[BufferIndex] != nullptr) + { + Buffer_SceneColor_Float[BufferIndex]->ClearFlags(RF_Standalone); + Buffer_SceneColor_Float[BufferIndex]->RemoveFromRoot(); + Buffer_SceneColor_Float[BufferIndex] = nullptr; + } if (Buffer_HDR_Float[BufferIndex] != nullptr) { Buffer_HDR_Float[BufferIndex]->ClearFlags(RF_Standalone); @@ -314,6 +528,7 @@ namespace PixelInspector ReleaseBuffers(LastBufferIndex); FTextureRenderTargetResource* FinalColorRenderTargetResource = nullptr; + FTextureRenderTargetResource* SceneColorRenderTargetResource = nullptr; FTextureRenderTargetResource* HDRRenderTargetResource = nullptr; FTextureRenderTargetResource* DepthRenderTargetResource = nullptr; FTextureRenderTargetResource* BufferARenderTargetResource = nullptr; @@ -327,6 +542,14 @@ namespace PixelInspector Buffer_FinalColor_RGB8[LastBufferIndex]->UpdateResourceImmediate(true); FinalColorRenderTargetResource = Buffer_FinalColor_RGB8[LastBufferIndex]->GameThread_GetRenderTargetResource(); + //Scene color is in RGB8 format + Buffer_SceneColor_Float[LastBufferIndex] = NewObject(GetTransientPackage(), TEXT("PixelInspectorBufferSceneColorTarget"), RF_Standalone); + Buffer_SceneColor_Float[LastBufferIndex]->AddToRoot(); + Buffer_SceneColor_Float[LastBufferIndex]->InitCustomFormat(1, 1, PF_FloatRGBA, true); + Buffer_SceneColor_Float[LastBufferIndex]->ClearColor = FLinearColor::Black; + Buffer_SceneColor_Float[LastBufferIndex]->UpdateResourceImmediate(true); + SceneColorRenderTargetResource = Buffer_SceneColor_Float[LastBufferIndex]->GameThread_GetRenderTargetResource(); + //HDR is in float RGB format Buffer_HDR_Float[LastBufferIndex] = NewObject(GetTransientPackage(), TEXT("PixelInspectorBufferHDRTarget"), RF_Standalone); Buffer_HDR_Float[LastBufferIndex]->AddToRoot(); @@ -341,8 +564,8 @@ namespace PixelInspector Buffer_Depth_Float[LastBufferIndex]->InitCustomFormat(1, 1, PF_DepthStencil, true); Buffer_Depth_Float[LastBufferIndex]->ClearColor = FLinearColor::Black; Buffer_Depth_Float[LastBufferIndex]->UpdateResourceImmediate(true); - DepthRenderTargetResource = Buffer_Depth_Float[LastBufferIndex]->GameThread_GetRenderTargetResource(); -*/ + DepthRenderTargetResource = Buffer_Depth_Float[LastBufferIndex]->GameThread_GetRenderTargetResource();*/ + //Low precision GBuffer if (GBufferFormat == 0) @@ -398,7 +621,7 @@ namespace PixelInspector BufferBCDERenderTargetResource = Buffer_BCDE_Float[LastBufferIndex]->GameThread_GetRenderTargetResource(); } - SceneInterface->InitializePixelInspector(FinalColorRenderTargetResource, DepthRenderTargetResource, HDRRenderTargetResource, BufferARenderTargetResource, BufferBCDERenderTargetResource, LastBufferIndex); + SceneInterface->InitializePixelInspector(FinalColorRenderTargetResource, SceneColorRenderTargetResource, DepthRenderTargetResource, HDRRenderTargetResource, BufferARenderTargetResource, BufferBCDERenderTargetResource, LastBufferIndex); return LastBufferIndex; } @@ -411,6 +634,10 @@ namespace PixelInspector { if (Requests[RequestIndex].FrameCountAfterRenderingCommandSend >= WAIT_FRAMENUMBER_BEFOREREADING) { + if (Requests[RequestIndex].SourcePixelPosition == FIntPoint(-1, -1)) + { + continue; + } PixelInspectorResult PixelResult; PixelResult.ScreenPosition = Requests[RequestIndex].SourcePixelPosition; PixelResult.ViewUniqueId = Requests[RequestIndex].ViewId; @@ -422,6 +649,14 @@ namespace PixelInspector BufferFinalColorValue.Empty(); } PixelResult.DecodeFinalColor(BufferFinalColorValue); + + TArray BufferSceneColorValue; + FTextureRenderTargetResource* RTResourceSceneColor = Buffer_SceneColor_Float[Requests[RequestIndex].BufferIndex]->GameThread_GetRenderTargetResource(); + if (RTResourceSceneColor->ReadLinearColorPixels(BufferSceneColorValue) == false) + { + BufferSceneColorValue.Empty(); + } + PixelResult.DecodeSceneColor(BufferSceneColorValue); if (Buffer_Depth_Float[Requests[RequestIndex].BufferIndex] != nullptr) { @@ -530,6 +765,11 @@ namespace PixelInspector } DisplayResult->SetFromResult(AccumulationResult[0]); DisplayDetailsView->SetObject(DisplayResult, true); + if (AccumulationResult[0].ScreenPosition != LastViewportInspectionPosition) + { + LastViewportInspectionPosition = AccumulationResult[0].ScreenPosition; + } + LastViewportId = AccumulationResult[0].ViewUniqueId; AccumulationResult.RemoveAt(0); } } diff --git a/Engine/Source/Editor/PixelInspector/Private/PixelInspector.h b/Engine/Source/Editor/PixelInspector/Private/PixelInspector.h index 31adba511f15..462a7cb60d0a 100644 --- a/Engine/Source/Editor/PixelInspector/Private/PixelInspector.h +++ b/Engine/Source/Editor/PixelInspector/Private/PixelInspector.h @@ -48,10 +48,31 @@ namespace PixelInspector void OnApplicationPreInputKeyDownListener(const FKeyEvent& InKeyEvent); /** Button handlers */ - ECheckBoxState IsPixelInspectorEnable() const; - void HandleTogglePixelInspectorEnable(ECheckBoxState CheckType); + FReply HandleTogglePixelInspectorEnableButton(); + FText GetPixelInspectorEnableButtonText() const; + FText GetPixelInspectorEnableButtonTooltipText() const; + const FSlateBrush* GetPixelInspectorEnableButtonBrush() const; + + + TOptional GetCurrentViewportId() const { return LastViewportId; } + FIntPoint GetCurrentCoordinate() const { return LastViewportInspectionPosition; } + TOptional GetCurrentCoordinateX() const { return LastViewportInspectionPosition.X; } + void SetCurrentCoordinateX(int32 NewValue); + void SetCurrentCoordinateXCommit(int32 NewValue, ETextCommit::Type); + TOptional GetCurrentCoordinateY() const { return LastViewportInspectionPosition.Y; } + void SetCurrentCoordinateY(int32 NewValue); + void SetCurrentCoordinateYCommit(int32 NewValue, ETextCommit::Type); + TOptional GetMaxCoordinateX() const; + TOptional GetMaxCoordinateY() const; + /** End button handlers */ + bool IsPixelInspectorEnable() const { return bIsPixelInspectorEnable; } + + void SetCurrentCoordinate(FIntPoint NewCoordinate, bool ReleaseAllRequest); + + void SetViewportInformation(int32 ViewportUniqueId, FIntPoint ViewportSize) { LastViewportInspectionSize = ViewportSize; } + /* * Create a request and the associate buffers * @@ -88,7 +109,14 @@ namespace PixelInspector void ReleaseBuffers(int32 BufferIndex); void OnLevelActorDeleted(AActor* Actor); + void OnRedrawViewport(bool bInvalidateHitProxies); + + /* + * Use by the Coordinate mode only, this change the realtime state of the viewport if the state is not true + */ + void SetCurrentViewportInRealtime(); + private: void ReleaseAllRequests(); @@ -109,6 +137,8 @@ namespace PixelInspector UTextureRenderTarget2D* Buffer_FinalColor_RGB8[2]; //Depth Buffer UTextureRenderTarget2D* Buffer_Depth_Float[2]; + //SceneColor Buffer + UTextureRenderTarget2D* Buffer_SceneColor_Float[2]; //HDR Buffer UTextureRenderTarget2D* Buffer_HDR_Float[2]; //GBufferA RenderTarget @@ -127,7 +157,15 @@ namespace PixelInspector ////////////////////////////////////////////////////////////////////////// // Display UObject to use the Detail Property Widget + UPixelInspectorView *DisplayResult; + + FIntPoint LastViewportInspectionSize; + + FIntPoint LastViewportInspectionPosition; + + uint32 LastViewportId; + TSharedPtr DisplayDetailsView; }; } diff --git a/Engine/Source/Editor/PixelInspector/Private/PixelInspectorDetailsCustomization.cpp b/Engine/Source/Editor/PixelInspector/Private/PixelInspectorDetailsCustomization.cpp index 721f5a76ea79..54e8d68ec341 100644 --- a/Engine/Source/Editor/PixelInspector/Private/PixelInspectorDetailsCustomization.cpp +++ b/Engine/Source/Editor/PixelInspector/Private/PixelInspectorDetailsCustomization.cpp @@ -8,6 +8,7 @@ #include "DetailCategoryBuilder.h" #include "DetailWidgetRow.h" #include "PropertyHandle.h" +#include "PixelInspectorModule.h" #define LOCTEXT_NAMESPACE "PixelInspector" @@ -25,7 +26,7 @@ TSharedRef FPixelInspectorDetailsCustomization::MakeInstan TSharedRef FPixelInspectorDetailsCustomization::GetGridColorContext() { TSharedRef HorizontalMainGrid = SNew(SHorizontalBox); - for (int RowIndex = 0; RowIndex < FinalColorContextGridSize; ++RowIndex) + for (int32 ColumnIndex = 0; ColumnIndex < FinalColorContextGridSize; ++ColumnIndex) { SBoxPanel::FSlot &HorizontalSlot = HorizontalMainGrid->AddSlot() .AutoWidth() @@ -34,7 +35,7 @@ TSharedRef FPixelInspectorDetailsCustomization::GetGridColorCont .HAlign(HAlign_Center); TSharedRef VerticalColumn = SNew(SVerticalBox); - for (int ColumnIndex = 0; ColumnIndex < FinalColorContextGridSize; ++ColumnIndex) + for (int32 RowIndex = 0; RowIndex < FinalColorContextGridSize; ++RowIndex) { VerticalColumn->AddSlot() .AutoHeight() @@ -42,7 +43,7 @@ TSharedRef FPixelInspectorDetailsCustomization::GetGridColorCont .VAlign(VAlign_Center) .HAlign(HAlign_Center) [ - CreateColorCell(PixelInspectorView->FinalColorContext[RowIndex + ColumnIndex*FinalColorContextGridSize]) + CreateColorCell(RowIndex, ColumnIndex, PixelInspectorView->FinalColorContext[ColumnIndex + RowIndex*FinalColorContextGridSize]) ]; } HorizontalSlot[VerticalColumn]; @@ -50,14 +51,52 @@ TSharedRef FPixelInspectorDetailsCustomization::GetGridColorCont return HorizontalMainGrid; } - -TSharedRef FPixelInspectorDetailsCustomization::CreateColorCell(const FLinearColor &CellColor) +FReply FPixelInspectorDetailsCustomization::HandleColorCellMouseButtonDown(const FGeometry &, const FPointerEvent &, int32 RowIndex, int32 ColumnIndex) { + //Send a create a request to the new Coordinate + if (RowIndex < 0 || RowIndex > FinalColorContextGridSize || + ColumnIndex < 0 || ColumnIndex > FinalColorContextGridSize) + return FReply::Handled(); + + int32 DeltaX = ColumnIndex - FMath::FloorToInt((float)FinalColorContextGridSize / 2.0f); + int32 DeltaY = RowIndex - FMath::FloorToInt((float)FinalColorContextGridSize / 2.0f); + //If user click on the middle do nothing + if (DeltaX == 0 && DeltaY == 0) + return FReply::Handled(); + //Get the PixelInspector module + FPixelInspectorModule* PixelInspectorModule = &FModuleManager::LoadModuleChecked(TEXT("PixelInspectorModule")); + if (PixelInspectorModule != nullptr) + { + FIntPoint InspectViewportPos = FIntPoint(-1, -1); + uint32 CoordinateViewportId = 0; + PixelInspectorModule->GetCoordinatePosition(InspectViewportPos, CoordinateViewportId); + if (InspectViewportPos == FIntPoint(-1, -1)) + return FReply::Handled(); + + InspectViewportPos.X += DeltaX; + InspectViewportPos.Y += DeltaY; + if (InspectViewportPos.X < 0 || InspectViewportPos.Y < 0) + return FReply::Handled(); + + bool IsInspectorActive = PixelInspectorModule->IsPixelInspectorEnable(); + if (!IsInspectorActive) + { + PixelInspectorModule->ActivateCoordinateMode(); + } + PixelInspectorModule->SetCoordinatePosition(InspectViewportPos, true); + } + return FReply::Handled(); +} + +TSharedRef FPixelInspectorDetailsCustomization::CreateColorCell(int32 RowIndex, int32 ColumnIndex, const FLinearColor &CellColor) +{ + int32 SquareSize = FMath::FloorToInt(80.0f / (float)FinalColorContextGridSize); return SNew(SColorBlock) .Color(CellColor) .ShowBackgroundForAlpha(false) .IgnoreAlpha(true) - .Size(FVector2D(16.0f, 16.0f)); + .Size(FVector2D(SquareSize, SquareSize)) + .OnMouseButtonDown(this, &FPixelInspectorDetailsCustomization::HandleColorCellMouseButtonDown, RowIndex, ColumnIndex); } void FPixelInspectorDetailsCustomization::CustomizeDetails(IDetailLayoutBuilder& DetailBuilder) @@ -70,7 +109,7 @@ void FPixelInspectorDetailsCustomization::CustomizeDetails(IDetailLayoutBuilder& PixelInspectorView = Cast(EditingObjects[0].Get()); IDetailCategoryBuilder& FinalColorCategory = DetailBuilder.EditCategory("FinalColor", FText::GetEmpty()); - if (PixelInspectorView != nullptr) + if (PixelInspectorView.IsValid() ) { FDetailWidgetRow& MergeRow = FinalColorCategory.AddCustomRow(LOCTEXT("FinalColorContextArray", "Context Color")) .NameContent() diff --git a/Engine/Source/Editor/PixelInspector/Private/PixelInspectorDetailsCustomization.h b/Engine/Source/Editor/PixelInspector/Private/PixelInspectorDetailsCustomization.h index 7c585191fb06..ef0ff54c6d58 100644 --- a/Engine/Source/Editor/PixelInspector/Private/PixelInspectorDetailsCustomization.h +++ b/Engine/Source/Editor/PixelInspector/Private/PixelInspectorDetailsCustomization.h @@ -19,8 +19,10 @@ public: private: + FReply HandleColorCellMouseButtonDown(const FGeometry &, const FPointerEvent &, int32 RowIndex, int32 ColumnIndex); + TSharedRef GetGridColorContext(); - TSharedRef CreateColorCell(const FLinearColor &CellColor); + TSharedRef CreateColorCell(int32 RowIndex, int32 ColumnIndex, const FLinearColor &CellColor); /** Use MakeInstance to create an instance of this class */ FPixelInspectorDetailsCustomization(); diff --git a/Engine/Source/Editor/PixelInspector/Private/PixelInspectorModule.cpp b/Engine/Source/Editor/PixelInspector/Private/PixelInspectorModule.cpp index 7bf4089f7faf..8e8d800ee5c4 100644 --- a/Engine/Source/Editor/PixelInspector/Private/PixelInspectorModule.cpp +++ b/Engine/Source/Editor/PixelInspector/Private/PixelInspectorModule.cpp @@ -26,9 +26,34 @@ TSharedRef FPixelInspectorModule::CreatePixelInspectorWidget() return HPixelInspectorWindow->AsShared(); } +void FPixelInspectorModule::ActivateCoordinateMode() +{ + if (!HPixelInspectorWindow.IsValid()) + return; + HPixelInspectorWindow->HandleTogglePixelInspectorEnableButton(); +} + bool FPixelInspectorModule::IsPixelInspectorEnable() { - return HPixelInspectorWindow.IsValid() ? HPixelInspectorWindow->IsPixelInspectorEnable() == ECheckBoxState::Checked : false; + if (!HPixelInspectorWindow.IsValid()) + return false; + return HPixelInspectorWindow->IsPixelInspectorEnable(); +} + +void FPixelInspectorModule::GetCoordinatePosition(FIntPoint &InspectViewportCoordinate, uint32 &InspectViewportId) +{ + InspectViewportCoordinate = FIntPoint(-1, -1); + if (!HPixelInspectorWindow.IsValid()) + return; + InspectViewportId = HPixelInspectorWindow->GetCurrentViewportId().GetValue(); + InspectViewportCoordinate = HPixelInspectorWindow->GetCurrentCoordinate(); +} + +void FPixelInspectorModule::SetCoordinatePosition(FIntPoint &InspectViewportCoordinate, bool ReleaseAllRequest) +{ + if (!HPixelInspectorWindow.IsValid()) + return; + HPixelInspectorWindow->SetCurrentCoordinate(InspectViewportCoordinate, ReleaseAllRequest); } bool FPixelInspectorModule::GetViewportRealtime(int32 ViewportUid, bool IsCurrentlyRealtime, bool IsMouseInsideViewport) @@ -57,13 +82,22 @@ bool FPixelInspectorModule::GetViewportRealtime(int32 ViewportUid, bool IsCurren return IsCurrentlyRealtime; } -void FPixelInspectorModule::CreatePixelInspectorRequest(FIntPoint ScreenPosition, int32 viewportUniqueId, FSceneInterface *SceneInterface) +void FPixelInspectorModule::CreatePixelInspectorRequest(FIntPoint ScreenPosition, int32 ViewportUniqueId, FSceneInterface *SceneInterface) { if (HPixelInspectorWindow.IsValid() == false) { return; } - HPixelInspectorWindow->CreatePixelInspectorRequest(ScreenPosition, viewportUniqueId, SceneInterface); + HPixelInspectorWindow->CreatePixelInspectorRequest(ScreenPosition, ViewportUniqueId, SceneInterface); +} + +void FPixelInspectorModule::SetViewportInformation(int32 ViewportUniqueId, FIntPoint ViewportSize) +{ + if (HPixelInspectorWindow.IsValid() == false) + { + return; + } + HPixelInspectorWindow->SetViewportInformation(ViewportUniqueId, ViewportSize); } void FPixelInspectorModule::ReadBackSync() diff --git a/Engine/Source/Editor/PixelInspector/Private/PixelInspectorResult.cpp b/Engine/Source/Editor/PixelInspector/Private/PixelInspectorResult.cpp index 7a94a3af612f..5fca132f854a 100644 --- a/Engine/Source/Editor/PixelInspector/Private/PixelInspectorResult.cpp +++ b/Engine/Source/Editor/PixelInspector/Private/PixelInspectorResult.cpp @@ -28,6 +28,17 @@ namespace PixelInspector FinalColor.Add(LinearColor); } } + void PixelInspectorResult::DecodeSceneColor(TArray &BufferSceneColorValue) + { + if (BufferSceneColorValue.Num() <= 0) + { + SceneColor = FLinearColor::Black; + return; + } + SceneColor = BufferSceneColorValue[0]; + //Set the alpha to 1.0 as the default value + SceneColor.A = 1.0f; + } void PixelInspectorResult::DecodeDepth(TArray &BufferDepthValue) { if (BufferDepthValue.Num() <= 0) diff --git a/Engine/Source/Editor/PixelInspector/Private/PixelInspectorResult.h b/Engine/Source/Editor/PixelInspector/Private/PixelInspectorResult.h index 8d10055c40ba..302b91f1d67e 100644 --- a/Engine/Source/Editor/PixelInspector/Private/PixelInspectorResult.h +++ b/Engine/Source/Editor/PixelInspector/Private/PixelInspectorResult.h @@ -62,6 +62,10 @@ namespace PixelInspector // Final color 3x3 grid TArray FinalColor; + ////////////////////////////////////////////////////////////////////////// + // Scene color + FLinearColor SceneColor; + ////////////////////////////////////////////////////////////////////////// // Depth and world position float Depth; @@ -116,6 +120,7 @@ namespace PixelInspector float IrisDistance; void DecodeFinalColor(TArray &BufferFinalColorValue); + void DecodeSceneColor(TArray &BufferSceneColorValue); void DecodeDepth(TArray &BufferDepthValue); void DecodeHDR(TArray &BufferHDRValue); diff --git a/Engine/Source/Editor/PixelInspector/Private/PixelInspectorStyle.cpp b/Engine/Source/Editor/PixelInspector/Private/PixelInspectorStyle.cpp index 59c4196c014b..7d673dbc4d43 100644 --- a/Engine/Source/Editor/PixelInspector/Private/PixelInspectorStyle.cpp +++ b/Engine/Source/Editor/PixelInspector/Private/PixelInspectorStyle.cpp @@ -54,6 +54,8 @@ void FPixelInspectorStyle::Initialize() // PixelInspector Icons { StyleSet->Set( "PixelInspector.TabIcon", new IMAGE_BRUSH( "Icons/PixelInspector/icon_PixelInspector_tab_16x", Icon16x16 ) ); + StyleSet->Set( "PixelInspector.Enabled", new IMAGE_BRUSH( "Icons/PixelInspector/icon_PixelInspector_Stop_16x", Icon16x16 ) ); + StyleSet->Set( "PixelInspector.Disabled", new IMAGE_BRUSH( "Icons/PixelInspector/icon_PixelInspector_Start_16x", Icon16x16 ) ); } FSlateStyleRegistry::RegisterSlateStyle( *StyleSet.Get() ); diff --git a/Engine/Source/Editor/PixelInspector/Private/PixelInspectorView.cpp b/Engine/Source/Editor/PixelInspector/Private/PixelInspectorView.cpp index 9c4fb7fb06ff..19449b5da66a 100644 --- a/Engine/Source/Editor/PixelInspector/Private/PixelInspectorView.cpp +++ b/Engine/Source/Editor/PixelInspector/Private/PixelInspectorView.cpp @@ -7,13 +7,12 @@ UPixelInspectorView::UPixelInspectorView(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { - ViewportId = -1; - PixelScreenPosition = FIntPoint(-1, -1); for (int i = 0; i < FinalColorContextGridSize*FinalColorContextGridSize; ++i) { FinalColorContext[i] = FLinearColor::Green; } FinalColor = FLinearColor::Green; + SceneColor = FLinearColor::Green; Luminance = 0.0f; HdrColor = FLinearColor::Black; Normal = FVector(0.0f); @@ -43,8 +42,6 @@ UPixelInspectorView::UPixelInspectorView(const FObjectInitializer& ObjectInitial void UPixelInspectorView::SetFromResult(PixelInspector::PixelInspectorResult &Result) { - ViewportId = Result.ViewUniqueId; - PixelScreenPosition = Result.ScreenPosition; FinalColor = FLinearColor::Green; //Take the center of the array, TODO display the context for (int i = 0; i < FinalColorContextGridSize*FinalColorContextGridSize; ++i) @@ -63,6 +60,7 @@ void UPixelInspectorView::SetFromResult(PixelInspector::PixelInspectorResult &Re } } + SceneColor = Result.SceneColor; Luminance = Result.HdrLuminance; HdrColor = Result.HdrColor; Normal = Result.Normal; diff --git a/Engine/Source/Editor/PixelInspector/Private/PixelInspectorView.h b/Engine/Source/Editor/PixelInspector/Private/PixelInspectorView.h index 14f4921d54ef..236300e9f76b 100644 --- a/Engine/Source/Editor/PixelInspector/Private/PixelInspectorView.h +++ b/Engine/Source/Editor/PixelInspector/Private/PixelInspectorView.h @@ -3,7 +3,7 @@ #pragma once #include "PixelInspectorView.generated.h" -#define FinalColorContextGridSize 5 +#define FinalColorContextGridSize 7 UCLASS(HideCategories = Object, MinimalAPI) class UPixelInspectorView : public UObject @@ -12,18 +12,14 @@ class UPixelInspectorView : public UObject FLinearColor FinalColorContext[FinalColorContextGridSize*FinalColorContextGridSize]; - /** The viewport id from where the pixel was inspect. */ - UPROPERTY(VisibleAnywhere, category = Identification) - int32 ViewportId; - - /** The pixel relative to the inspected viewport. */ - UPROPERTY(VisibleAnywhere, category = Identification) - FIntPoint PixelScreenPosition; - /** Final RGBA 8bits Color after tone mapping, default value is black. */ UPROPERTY(VisibleAnywhere, category = FinalColor) FLinearColor FinalColor; + /** HDR RGB Color. */ + UPROPERTY(VisibleAnywhere, category = SceneColor) + FLinearColor SceneColor; + /** HDR Luminance. */ UPROPERTY(VisibleAnywhere, category = HDR) float Luminance; @@ -118,7 +114,6 @@ class UPixelInspectorView : public UObject UPROPERTY(VisibleAnywhere, category = GBufferD) float IrisDistance; - void SetFromResult(PixelInspector::PixelInspectorResult &Result); /* ////////////////////////////////////////////////////////////////////////// diff --git a/Engine/Source/Editor/PixelInspector/Public/PixelInspectorModule.h b/Engine/Source/Editor/PixelInspector/Public/PixelInspectorModule.h index 6a9716d6d893..c35fbf5ddddf 100644 --- a/Engine/Source/Editor/PixelInspector/Public/PixelInspectorModule.h +++ b/Engine/Source/Editor/PixelInspector/Public/PixelInspectorModule.h @@ -1,5 +1,7 @@ // Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. +#pragma once + #include "ModuleInterface.h" #include "UnrealEd.h" @@ -11,6 +13,7 @@ namespace PixelInspector { class SPixelInspector; }; */ class FPixelInspectorModule : public IModuleInterface { + public: /** * Called right after the module DLL has been loaded and the module object has been created @@ -25,11 +28,19 @@ public: /** Creates the HLOD Outliner widget */ virtual TSharedRef CreatePixelInspectorWidget(); + virtual void ActivateCoordinateMode(); + virtual bool IsPixelInspectorEnable(); + virtual void GetCoordinatePosition(FIntPoint &InspectViewportCoordinate, uint32 &InspectViewportId); + + virtual void SetCoordinatePosition(FIntPoint &InspectViewportCoordinate, bool ReleaseAllRequest); + virtual bool GetViewportRealtime(int32 ViewportUid, bool IsCurrentlyRealtime, bool IsMouseInsideViewport); - virtual void CreatePixelInspectorRequest(FIntPoint ScreenPosition, int32 viewportUniqueId, FSceneInterface *SceneInterface); + virtual void CreatePixelInspectorRequest(FIntPoint ScreenPosition, int32 ViewportUniqueId, FSceneInterface *SceneInterface); + + virtual void SetViewportInformation(int32 ViewportUniqueId, FIntPoint ViewportSize); virtual void ReadBackSync(); diff --git a/Engine/Source/Editor/PropertyEditor/Private/DetailCategoryBuilderImpl.cpp b/Engine/Source/Editor/PropertyEditor/Private/DetailCategoryBuilderImpl.cpp index 4a7bbbe0d039..21419466cf4d 100644 --- a/Engine/Source/Editor/PropertyEditor/Private/DetailCategoryBuilderImpl.cpp +++ b/Engine/Source/Editor/PropertyEditor/Private/DetailCategoryBuilderImpl.cpp @@ -511,6 +511,12 @@ bool FDetailCategoryImpl::ContainsOnlyAdvanced() const return !bFavoriteCategory && SimpleChildNodes.Num() == 0 && AdvancedChildNodes.Num() > 0; } +void FDetailCategoryImpl::GetCategoryInformation(int32 &SimpleChildNum, int32 &AdvanceChildNum) const +{ + SimpleChildNum = SimpleChildNodes.Num(); + AdvanceChildNum = AdvancedChildNodes.Num(); +} + void FDetailCategoryImpl::SetDisplayName( FName InCategoryName, const FText& LocalizedNameOverride ) { if( !LocalizedNameOverride.IsEmpty() ) diff --git a/Engine/Source/Editor/PropertyEditor/Private/DetailCategoryBuilderImpl.h b/Engine/Source/Editor/PropertyEditor/Private/DetailCategoryBuilderImpl.h index d9d4271fe5b4..3dd0a00e86be 100644 --- a/Engine/Source/Editor/PropertyEditor/Private/DetailCategoryBuilderImpl.h +++ b/Engine/Source/Editor/PropertyEditor/Private/DetailCategoryBuilderImpl.h @@ -248,6 +248,9 @@ public: /** @return true if this category only contains advanced properties */ bool ContainsOnlyAdvanced() const; + /** @return true if this category only contains advanced properties */ + void GetCategoryInformation(int32 &SimpleChildNum, int32 &AdvanceChildNum) const; + /** * Called when the advanced dropdown button is clicked */ diff --git a/Engine/Source/Editor/PropertyEditor/Private/DetailLayoutBuilderImpl.cpp b/Engine/Source/Editor/PropertyEditor/Private/DetailLayoutBuilderImpl.cpp index e6463b0c25cc..f5bd88d7d366 100644 --- a/Engine/Source/Editor/PropertyEditor/Private/DetailLayoutBuilderImpl.cpp +++ b/Engine/Source/Editor/PropertyEditor/Private/DetailLayoutBuilderImpl.cpp @@ -119,6 +119,11 @@ FDetailCategoryImpl& FDetailLayoutBuilderImpl::DefaultCategory( FName CategoryNa return *CategoryImpl; } +bool FDetailLayoutBuilderImpl::HasCategory(FName CategoryName) +{ + return DefaultCategoryMap.Contains(CategoryName); +} + void FDetailLayoutBuilderImpl::BuildCategories( const FCategoryMap& CategoryMap, TArray< TSharedRef >& OutSimpleCategories, TArray< TSharedRef >& OutAdvancedCategories ) { for( FCategoryMap::TConstIterator It(CategoryMap); It; ++It ) diff --git a/Engine/Source/Editor/PropertyEditor/Private/DetailLayoutBuilderImpl.h b/Engine/Source/Editor/PropertyEditor/Private/DetailLayoutBuilderImpl.h index c50ccb6e1979..c21adc200cc8 100644 --- a/Engine/Source/Editor/PropertyEditor/Private/DetailLayoutBuilderImpl.h +++ b/Engine/Source/Editor/PropertyEditor/Private/DetailLayoutBuilderImpl.h @@ -29,6 +29,11 @@ public: */ FDetailCategoryImpl& DefaultCategory( FName CategoryName ); + /** + * Return true if the category exist + */ + bool HasCategory(FName CategoryName); + /** * Generates the layout for this detail builder */ diff --git a/Engine/Source/Editor/PropertyEditor/Private/IDetailsViewPrivate.h b/Engine/Source/Editor/PropertyEditor/Private/IDetailsViewPrivate.h index c48f08c475a4..33aef37c44e2 100644 --- a/Engine/Source/Editor/PropertyEditor/Private/IDetailsViewPrivate.h +++ b/Engine/Source/Editor/PropertyEditor/Private/IDetailsViewPrivate.h @@ -56,6 +56,18 @@ public: /** Causes the details view to be refreshed (new widgets generated) with the current set of objects */ virtual void ForceRefresh() = 0; + /** Causes the details view to move the scroll offset (by item) + * @param DeltaOffset We add this value to the current scroll offset if the result is in the scrolling range + */ + virtual void MoveScrollOffset(int32 DeltaOffset) = 0; + + /* Return true if the category exist in the detail view + * @param CategoryName The name of the category we need informations + * @param SimplePropertiesNum The Number of basic properties contain in the category + * @param AdvancePropertiesNum The Number of advance properties contain in the category + */ + virtual bool GetCategoryInfo(FName CategoryName, int32 &SimplePropertiesNum, int32 &AdvancePropertiesNum) { SimplePropertiesNum = 0; AdvancePropertiesNum = 0; return false; } + /** * Saves the expansion state of a tree node * diff --git a/Engine/Source/Editor/PropertyEditor/Private/PropertyHandleImpl.cpp b/Engine/Source/Editor/PropertyEditor/Private/PropertyHandleImpl.cpp index 2bcfaadee64c..b1265a37c8c4 100644 --- a/Engine/Source/Editor/PropertyEditor/Private/PropertyHandleImpl.cpp +++ b/Engine/Source/Editor/PropertyEditor/Private/PropertyHandleImpl.cpp @@ -1854,6 +1854,20 @@ void FPropertyHandleBase::SetToolTipText( const FText& ToolTip ) } } +int32 FPropertyHandleBase::GetNumPerObjectValues() const +{ + TSharedPtr PropertyNode = Implementation->GetPropertyNode(); + if (PropertyNode.IsValid() && PropertyNode->GetProperty()) + { + FComplexPropertyNode* ComplexNode = PropertyNode->FindComplexParent(); + if (ComplexNode) + { + return ComplexNode->GetInstancesNum(); + } + } + return 0; +} + FPropertyAccess::Result FPropertyHandleBase::SetPerObjectValues( const TArray& InPerObjectValues, EPropertyValueSetFlags::Type Flags ) { TSharedPtr PropertyNode = Implementation->GetPropertyNode(); @@ -1875,7 +1889,7 @@ FPropertyAccess::Result FPropertyHandleBase::SetPerObjectValues( const TArray& OutPerObjectValues ) +FPropertyAccess::Result FPropertyHandleBase::GetPerObjectValues( TArray& OutPerObjectValues ) const { FPropertyAccess::Result Result = FPropertyAccess::Fail; TSharedPtr PropertyNode = Implementation->GetPropertyNode(); @@ -1889,20 +1903,19 @@ FPropertyAccess::Result FPropertyHandleBase::GetPerObjectValues( TArray if( ReadAddresses.Num() > 0 ) { - // Create a list of object names. - TArray ObjectNames; - ObjectNames.Empty( ReadAddresses.Num() ); - - // Copy each object's object property name off into the name list. + // Copy each object's value into the value list + OutPerObjectValues.SetNum( ReadAddresses.Num(), /*bAllowShrinking*/false ); for ( int32 AddrIndex = 0 ; AddrIndex < ReadAddresses.Num() ; ++AddrIndex ) { uint8* Address = ReadAddresses.GetAddress(AddrIndex); - - new( OutPerObjectValues ) FString(); if( Address ) { NodeProperty->ExportText_Direct(OutPerObjectValues[AddrIndex], Address, Address, nullptr, 0 ); } + else + { + OutPerObjectValues[AddrIndex].Reset(); + } } Result = FPropertyAccess::Success; @@ -1912,6 +1925,67 @@ FPropertyAccess::Result FPropertyHandleBase::GetPerObjectValues( TArray return Result; } +FPropertyAccess::Result FPropertyHandleBase::SetPerObjectValue( const int32 ObjectIndex, const FString& ObjectValue, EPropertyValueSetFlags::Type Flags ) +{ + FPropertyAccess::Result Result = FPropertyAccess::Fail; + + TSharedPtr PropertyNode = Implementation->GetPropertyNode(); + if (PropertyNode.IsValid() && PropertyNode->GetProperty()) + { + Implementation->EnumerateObjectsToModify(PropertyNode.Get(), [&](const FObjectBaseAddress& ObjectToModify, const int32 ObjIndex, const int32 NumObjects) -> bool + { + if (ObjIndex == ObjectIndex) + { + TArray ObjectsToModify; + ObjectsToModify.Add(ObjectToModify); + + TArray PerObjectValues; + PerObjectValues.Add(ObjectValue); + + Implementation->ImportText(ObjectsToModify, PerObjectValues, PropertyNode.Get(), Flags); + + Result = FPropertyAccess::Success; + return false; // End enumeration + } + return true; + }); + } + + return Result; +} + +FPropertyAccess::Result FPropertyHandleBase::GetPerObjectValue( const int32 ObjectIndex, FString& OutObjectValue ) const +{ + FPropertyAccess::Result Result = FPropertyAccess::Fail; + + TSharedPtr PropertyNode = Implementation->GetPropertyNode(); + if (PropertyNode.IsValid() && PropertyNode->GetProperty()) + { + // Get a list of addresses for objects handled by the property window. + FReadAddressList ReadAddresses; + PropertyNode->GetReadAddress(!!PropertyNode->HasNodeFlags(EPropertyNodeFlags::SingleSelectOnly), ReadAddresses, false); + + UProperty* NodeProperty = PropertyNode->GetProperty(); + + if (ReadAddresses.IsValidIndex(ObjectIndex)) + { + uint8* Address = ReadAddresses.GetAddress(ObjectIndex); + if (Address) + { + NodeProperty->ExportText_Direct(OutObjectValue, Address, Address, nullptr, 0); + } + else + { + OutObjectValue.Reset(); + } + + Result = FPropertyAccess::Success; + } + } + + return Result; +} + TArray GetValidEnumEntries(UProperty* Property, const UEnum* InEnum) { TArray ValidEnumValues; diff --git a/Engine/Source/Editor/PropertyEditor/Private/PropertyHandleImpl.h b/Engine/Source/Editor/PropertyEditor/Private/PropertyHandleImpl.h index 63b8202e0ef9..c5472d8de4b9 100644 --- a/Engine/Source/Editor/PropertyEditor/Private/PropertyHandleImpl.h +++ b/Engine/Source/Editor/PropertyEditor/Private/PropertyHandleImpl.h @@ -425,8 +425,11 @@ public: virtual const FString* GetInstanceMetaData(const FName& Key) const override; virtual FText GetToolTipText() const override; virtual void SetToolTipText(const FText& ToolTip) override; + virtual int32 GetNumPerObjectValues() const override; virtual FPropertyAccess::Result SetPerObjectValues( const TArray& InPerObjectValues, EPropertyValueSetFlags::Type Flags = EPropertyValueSetFlags::DefaultFlags ) override; - virtual FPropertyAccess::Result GetPerObjectValues( TArray& OutPerObjectValues ) override; + virtual FPropertyAccess::Result GetPerObjectValues( TArray& OutPerObjectValues ) const override; + virtual FPropertyAccess::Result SetPerObjectValue( const int32 ObjectIndex, const FString& ObjectValue, EPropertyValueSetFlags::Type Flags = EPropertyValueSetFlags::DefaultFlags ) override; + virtual FPropertyAccess::Result GetPerObjectValue( const int32 ObjectIndex, FString& OutObjectValue ) const override; virtual bool GeneratePossibleValues(TArray< TSharedPtr >& OutOptionStrings, TArray< FText >& OutToolTips, TArray& OutRestrictedItems) override; virtual FPropertyAccess::Result SetObjectValueFromSelection() override; virtual void NotifyPreChange() override; diff --git a/Engine/Source/Editor/PropertyEditor/Private/PropertyNode.h b/Engine/Source/Editor/PropertyEditor/Private/PropertyNode.h index 027cdc6cefa8..b6aabb2895ad 100644 --- a/Engine/Source/Editor/PropertyEditor/Private/PropertyNode.h +++ b/Engine/Source/Editor/PropertyEditor/Private/PropertyNode.h @@ -113,6 +113,11 @@ public: return (Pair.Object.IsValid() || Pair.bIsStruct) ? Pair.ReadAddress : NULL; } + bool IsValidIndex( int32 Index ) const + { + return ReadAddresses.IsValidIndex(Index); + } + void Reset() { ReadAddresses.Reset(); @@ -146,6 +151,11 @@ public: { return ReadAddressListData->GetAddress( Index ); } + + bool IsValidIndex( int32 Index ) const + { + return ReadAddressListData->IsValidIndex( Index ); + } void Reset() { diff --git a/Engine/Source/Editor/PropertyEditor/Private/SDetailSingleItemRow.cpp b/Engine/Source/Editor/PropertyEditor/Private/SDetailSingleItemRow.cpp index 5570a972aa0d..56f8ce6cfcee 100644 --- a/Engine/Source/Editor/PropertyEditor/Private/SDetailSingleItemRow.cpp +++ b/Engine/Source/Editor/PropertyEditor/Private/SDetailSingleItemRow.cpp @@ -64,6 +64,28 @@ private: TAttribute< TOptional > MaxWidth; }; +namespace SDetailSingleItemRow_Helper +{ + //Get the node item number in case it is expand we have to recursively count all expanded children + void RecursivelyGetItemShow(TSharedRef ParentItem, int32 &ItemShowNum) + { + if (ParentItem->GetVisibility() == ENodeVisibility::Visible) + { + ItemShowNum++; + } + + if (ParentItem->ShouldBeExpanded()) + { + TArray< TSharedRef > Childrens; + ParentItem->GetChildren(Childrens); + for (TSharedRef ItemChild : Childrens) + { + RecursivelyGetItemShow(ItemChild, ItemShowNum); + } + } + } +} + FReply SDetailSingleItemRow::OnFavoriteToggle() { if (Customization->GetPropertyNode().IsValid() && Customization->GetPropertyNode()->CanDisplayFavorite()) @@ -72,6 +94,64 @@ FReply SDetailSingleItemRow::OnFavoriteToggle() Customization->GetPropertyNode()->SetFavorite(toggle); if (OwnerTreeNode.IsValid()) { + ////////////////////////////////////////////////////////////////////////// + // Calculate properly the scrolling offset (by item) to make sure the mouse stay over the same property + + //Get the node item number in case it is expand we have to recursively count all childrens + int32 ExpandSize = 0; + if (OwnerTreeNode.Pin()->ShouldBeExpanded()) + { + SDetailSingleItemRow_Helper::RecursivelyGetItemShow(OwnerTreeNode.Pin().ToSharedRef(), ExpandSize); + } + else + { + //if the item is not expand count is 1 + ExpandSize = 1; + } + + //Get the number of favorite child (simple and advance) to know if the favorite category will be create or remove + FString CategoryFavoritesName = TEXT("Favorites"); + FName CatFavName = *CategoryFavoritesName; + int32 SimplePropertiesNum = 0; + int32 AdvancePropertiesNum = 0; + bool HasCategoryFavorite = OwnerTreeNode.Pin()->GetDetailsView().GetCategoryInfo(CatFavName, SimplePropertiesNum, AdvancePropertiesNum); + + //Check if the property we toggle is an advance property + bool IsAdvanceProperty = Customization->GetPropertyNode()->HasNodeFlags(EPropertyNodeFlags::IsAdvanced) == 0 ? false : true; + + //Compute the scrolling offset by item + int32 ScrollingOffsetAdd = ExpandSize; + int32 ScrollingOffsetRemove = -ExpandSize; + if (HasCategoryFavorite) + { + //Adding the advance button in a category add 1 item + ScrollingOffsetAdd += (IsAdvanceProperty && AdvancePropertiesNum == 0) ? 1 : 0; + + if (IsAdvanceProperty && AdvancePropertiesNum == 1) + { + //Removing the advance button count as 1 item + ScrollingOffsetRemove -= 1; + } + if (AdvancePropertiesNum + SimplePropertiesNum == 1) + { + //Removing a full category count as 2 items + ScrollingOffsetRemove -= 2; + } + } + else + { + //Adding new category (2 items) adding advance button (1 item) + ScrollingOffsetAdd += IsAdvanceProperty ? 3 : 2; + + //We should never remove an item from favorite if there is no favorite category + //Set the remove offset to 0 + ScrollingOffsetRemove = 0; + } + + //Apply the calculated offset + OwnerTreeNode.Pin()->GetDetailsView().MoveScrollOffset(toggle ? ScrollingOffsetAdd : ScrollingOffsetRemove); + + //Refresh the tree OwnerTreeNode.Pin()->GetDetailsView().ForceRefresh(); } } diff --git a/Engine/Source/Editor/PropertyEditor/Private/SDetailsView.cpp b/Engine/Source/Editor/PropertyEditor/Private/SDetailsView.cpp index a89a748ed9c1..5aabf9b9e0cc 100644 --- a/Engine/Source/Editor/PropertyEditor/Private/SDetailsView.cpp +++ b/Engine/Source/Editor/PropertyEditor/Private/SDetailsView.cpp @@ -291,6 +291,22 @@ void SDetailsView::ForceRefresh() SetObjectArrayPrivate( NewObjectList ); } +void SDetailsView::MoveScrollOffset(int32 DeltaOffset) +{ + DetailTree->AddScrollOffset((float)DeltaOffset); +} + +bool SDetailsView::GetCategoryInfo(FName CategoryName, int32 &SimplePropertiesNum, int32 &AdvancePropertiesNum) +{ + SimplePropertiesNum = 0; + AdvancePropertiesNum = 0; + bool CategoryExist = DetailLayout.IsValid() ? DetailLayout->HasCategory(CategoryName) : false; + if (CategoryExist) + { + DetailLayout->DefaultCategory(CategoryName).GetCategoryInformation(SimplePropertiesNum, AdvancePropertiesNum); + } + return CategoryExist; +} void SDetailsView::SetObjects( const TArray& InObjects, bool bForceRefresh/* = false*/, bool bOverrideLock/* = false*/ ) { diff --git a/Engine/Source/Editor/PropertyEditor/Private/SDetailsView.h b/Engine/Source/Editor/PropertyEditor/Private/SDetailsView.h index 677161acb7d7..2fcb63254ea3 100644 --- a/Engine/Source/Editor/PropertyEditor/Private/SDetailsView.h +++ b/Engine/Source/Editor/PropertyEditor/Private/SDetailsView.h @@ -21,6 +21,12 @@ public: /** Causes the details view to be refreshed (new widgets generated) with the current set of objects */ void ForceRefresh() override; + /** Move the scrolling offset (by item), but do not refresh the tree*/ + void MoveScrollOffset(int32 DeltaOffset) override; + + /* Return true if the favorite category is currently displayed */ + bool GetCategoryInfo(FName CategoryName, int32 &SimplePropertiesNum, int32 &AdvancePropertiesNum) override; + /** * Constructs the property view widgets */ diff --git a/Engine/Source/Editor/PropertyEditor/Private/SDetailsViewBase.cpp b/Engine/Source/Editor/PropertyEditor/Private/SDetailsViewBase.cpp index 6c679f5bf46c..0995688e4183 100644 --- a/Engine/Source/Editor/PropertyEditor/Private/SDetailsViewBase.cpp +++ b/Engine/Source/Editor/PropertyEditor/Private/SDetailsViewBase.cpp @@ -1023,9 +1023,11 @@ void SDetailsViewBase::UpdatePropertyMapRecursive(FPropertyNode& InNode, FDetail { UProperty* ParentProperty = InNode.GetProperty(); UStructProperty* ParentStructProp = Cast(ParentProperty); - for (int32 ChildIndex = 0; ChildIndex < InNode.GetNumChildNodes(); ++ChildIndex) { + //Use the original value for each child + bool LocalUpdateFavoriteSystemOnly = bUpdateFavoriteSystemOnly; + TSharedPtr ChildNodePtr = InNode.GetChildNode(ChildIndex); FPropertyNode& ChildNode = *ChildNodePtr; UProperty* Property = ChildNode.GetProperty(); @@ -1037,11 +1039,11 @@ void SDetailsViewBase::UpdatePropertyMapRecursive(FPropertyNode& InNode, FDetail { // Currently object property nodes do not provide any useful information other than being a container for its children. We do not draw anything for them. // When we encounter object property nodes, add their children instead of adding them to the tree. - UpdatePropertyMapRecursive(ChildNode, InDetailLayout, CurCategory, ObjNode, bEnableFavoriteSystem, bUpdateFavoriteSystemOnly); + UpdatePropertyMapRecursive(ChildNode, InDetailLayout, CurCategory, ObjNode, bEnableFavoriteSystem, LocalUpdateFavoriteSystemOnly); } else if (CategoryNode) { - if (!bUpdateFavoriteSystemOnly) + if (!LocalUpdateFavoriteSystemOnly) { FName InstanceName = NAME_None; FName CategoryName = CurCategory; @@ -1056,7 +1058,7 @@ void SDetailsViewBase::UpdatePropertyMapRecursive(FPropertyNode& InNode, FDetail } // For category nodes, we just set the current category and recurse through the children - UpdatePropertyMapRecursive(ChildNode, InDetailLayout, CategoryNode->GetCategoryName(), CurObjectNode, bEnableFavoriteSystem, bUpdateFavoriteSystemOnly); + UpdatePropertyMapRecursive(ChildNode, InDetailLayout, CategoryNode->GetCategoryName(), CurObjectNode, bEnableFavoriteSystem, LocalUpdateFavoriteSystemOnly); } else { @@ -1108,7 +1110,7 @@ void SDetailsViewBase::UpdatePropertyMapRecursive(FPropertyNode& InNode, FDetail const bool bIsUserVisible = IsPropertyVisible(PropertyAndParent); // Inners of customized in structs should not be taken into consideration for customizing. They are not designed to be individually customized when their parent is already customized - if (!bIsChildOfCustomizedStruct && !bUpdateFavoriteSystemOnly) + if (!bIsChildOfCustomizedStruct && !LocalUpdateFavoriteSystemOnly) { // Add any object classes with properties so we can ask them for custom property layouts later ClassesWithProperties.Add(Property->GetOwnerStruct()); @@ -1126,7 +1128,7 @@ void SDetailsViewBase::UpdatePropertyMapRecursive(FPropertyNode& InNode, FDetail } // Do not add children of customized in struct properties or arrays - if (!bIsChildOfCustomizedStruct && !bIsChildOfArray && !bUpdateFavoriteSystemOnly) + if (!bIsChildOfCustomizedStruct && !bIsChildOfArray && !LocalUpdateFavoriteSystemOnly) { // Get the class property map FClassInstanceToPropertyMap& ClassInstanceMap = ClassToPropertyMap.FindOrAdd(Property->GetOwnerStruct()->GetFName()); @@ -1158,7 +1160,7 @@ void SDetailsViewBase::UpdatePropertyMapRecursive(FPropertyNode& InNode, FDetail CategoryName = PropertyCatagoryName; } - if (!bUpdateFavoriteSystemOnly) + if (!LocalUpdateFavoriteSystemOnly) { if (IsPropertyReadOnly(PropertyAndParent)) { @@ -1176,11 +1178,10 @@ void SDetailsViewBase::UpdatePropertyMapRecursive(FPropertyNode& InNode, FDetail if (bIsCustomizedStruct) { bCanDisplayFavorite = false; - //CustomizedStruct child are not categorize since they are under an object but we have to put them in favorite - UpdatePropertyMapRecursive(ChildNode, InDetailLayout, CurCategory, CurObjectNode, bEnableFavoriteSystem, true); + //CustomizedStruct child are not categorize since they are under an object but we have to put them in favorite category if the user want to favorite them + LocalUpdateFavoriteSystemOnly = true; } - - if (ChildNodePtr->IsFavorite()) + else if (ChildNodePtr->IsFavorite()) { //Find or create the favorite category, we have to duplicate favorite property row under this category FString CategoryFavoritesName = TEXT("Favorites"); @@ -1197,7 +1198,7 @@ void SDetailsViewBase::UpdatePropertyMapRecursive(FPropertyNode& InNode, FDetail RootInstanceName = RootObjectParent->GetObjectBaseClass()->GetFName(); } - if (bUpdateFavoriteSystemOnly) + if (LocalUpdateFavoriteSystemOnly) { if (IsPropertyReadOnly(PropertyAndParent)) { @@ -1230,10 +1231,10 @@ void SDetailsViewBase::UpdatePropertyMapRecursive(FPropertyNode& InNode, FDetail && bIsUserVisible // Properties must be allowed to be visible by a user if they are not then their children are not visible either && (!bIsStruct || bPushOutStructProps); // Only recurse into struct properties if they are going to be displayed as standalone properties in categories instead of inside an expandable area inside a category - if (bRecurseIntoChildren || bUpdateFavoriteSystemOnly) + if (bRecurseIntoChildren || LocalUpdateFavoriteSystemOnly) { // Built in struct properties or children of arras - UpdatePropertyMapRecursive(ChildNode, InDetailLayout, CurCategory, CurObjectNode, bEnableFavoriteSystem, bUpdateFavoriteSystemOnly); + UpdatePropertyMapRecursive(ChildNode, InDetailLayout, CurCategory, CurObjectNode, bEnableFavoriteSystem, LocalUpdateFavoriteSystemOnly); } } } diff --git a/Engine/Source/Editor/PropertyEditor/Private/SStructureDetailsView.h b/Engine/Source/Editor/PropertyEditor/Private/SStructureDetailsView.h index ed5aaee5fc3f..ceb0d94289ea 100644 --- a/Engine/Source/Editor/PropertyEditor/Private/SStructureDetailsView.h +++ b/Engine/Source/Editor/PropertyEditor/Private/SStructureDetailsView.h @@ -77,6 +77,7 @@ public: } virtual void ForceRefresh() override; + virtual void MoveScrollOffset(int32 DeltaOffset) override {} virtual void AddExternalRootPropertyNode(TSharedRef ExternalRootNode) override {} public: diff --git a/Engine/Source/Editor/PropertyEditor/Public/PropertyHandle.h b/Engine/Source/Editor/PropertyEditor/Public/PropertyHandle.h index 9da22f23b9c1..3d8441198da3 100644 --- a/Engine/Source/Editor/PropertyEditor/Public/PropertyHandle.h +++ b/Engine/Source/Editor/PropertyEditor/Public/PropertyHandle.h @@ -255,6 +255,11 @@ public: */ virtual FPropertyAccess::Result SetObjectValueFromSelection() = 0; + /** + * Gets the number of objects that this handle is editing + */ + virtual int32 GetNumPerObjectValues() const = 0; + /** * Sets a unique value for each object this handle is editing * @@ -265,7 +270,23 @@ public: /** * Gets a unique value for each object this handle is editing */ - virtual FPropertyAccess::Result GetPerObjectValues( TArray& OutPerObjectValues ) = 0; + virtual FPropertyAccess::Result GetPerObjectValues( TArray& OutPerObjectValues ) const = 0; + + /** + * Sets a value on the specified object that this handle is editing + * + * @param ObjectIndex The index of the object to set the value of + * @param ObjectValue The value to set on the given object + */ + virtual FPropertyAccess::Result SetPerObjectValue( const int32 ObjectIndex, const FString& ObjectValue, EPropertyValueSetFlags::Type Flags = EPropertyValueSetFlags::DefaultFlags ) = 0; + + /** + * Gets a value for the specified object that this handle is editing + * + * @param ObjectIndex The index of the object to get the value of + * @param OutObjectValue Filled with the value for this object + */ + virtual FPropertyAccess::Result GetPerObjectValue( const int32 ObjectIndex, FString& OutObjectValue ) const = 0; /** * @return The index of this element in an array if it is in one. INDEX_NONE otherwise diff --git a/Engine/Source/Editor/SequenceRecorder/Private/ActorRecording.cpp b/Engine/Source/Editor/SequenceRecorder/Private/ActorRecording.cpp index 80cdb52615f0..cd1faf6e81f7 100644 --- a/Engine/Source/Editor/SequenceRecorder/Private/ActorRecording.cpp +++ b/Engine/Source/Editor/SequenceRecorder/Private/ActorRecording.cpp @@ -271,7 +271,7 @@ void UActorRecording::StartRecordingActorProperties(ULevelSequence* CurrentSeque FString TemplateName = GetUniqueSpawnableName(MovieScene, Actor->GetName()); UClass* ActorClass = Actor->GetClass(); - AActor* ObjectTemplate = DuplicateObject(Actor, MovieScene, *TemplateName); + AActor* ObjectTemplate = CastChecked(StaticDuplicateObject(Actor, MovieScene, *TemplateName, RF_AllFlags & ~(RF_Transient))); if (ObjectTemplate) { diff --git a/Engine/Source/Editor/Sequencer/Private/SSequencer.cpp b/Engine/Source/Editor/Sequencer/Private/SSequencer.cpp index d83a90dfedac..ab9725da484a 100644 --- a/Engine/Source/Editor/Sequencer/Private/SSequencer.cpp +++ b/Engine/Source/Editor/Sequencer/Private/SSequencer.cpp @@ -582,7 +582,7 @@ void SSequencer::HandleLabelBrowserSelectionChanged(FString NewLabel, ESelectInf } else { - SearchBox->SetText(FText::FromString(FString(TEXT("label:")) + NewLabel)); + SearchBox->SetText(FText::FromString(NewLabel)); } } @@ -1180,7 +1180,7 @@ void SSequencer::OnOutlinerSearchChanged( const FText& Filter ) if ( FilterString.StartsWith( TEXT( "label:" ) ) ) { - LabelBrowser->SetSelectedLabel( FilterString.RightChop( 6 ) ); + LabelBrowser->SetSelectedLabel(FilterString); } else { diff --git a/Engine/Source/Editor/Sequencer/Private/SSequencerLabelBrowser.cpp b/Engine/Source/Editor/Sequencer/Private/SSequencerLabelBrowser.cpp index b95f6f4d50a5..2494f7d109e4 100644 --- a/Engine/Source/Editor/Sequencer/Private/SSequencerLabelBrowser.cpp +++ b/Engine/Source/Editor/Sequencer/Private/SSequencerLabelBrowser.cpp @@ -32,7 +32,7 @@ void SSequencerLabelBrowser::Construct(const FArguments& InArgs, TSharedRefLabel == Label) - { - LabelTreeView->SetSelection(Node); + TArray SplitLabelStrings; + Label.ParseIntoArray(SplitLabelStrings, TEXT(" ")); - return; - } + TArray SelectedLabels; + for (FString LabelString : SplitLabelStrings) + { + if (LabelString.StartsWith(TEXT("label:"))) + { + LabelString = LabelString.RightChop( 6 ); + SelectedLabels.Add(LabelString); } } LabelTreeView->ClearSelection(); + + for (auto& Node : LabelList) + { + if (SelectedLabels.Contains(Node->Label)) + { + LabelTreeView->SetItemSelection(Node, true); + } + } } @@ -197,9 +205,26 @@ void SSequencerLabelBrowser::HandleLabelTreeViewGetChildren(TSharedPtr InItem, ESelectInfo::Type SelectInfo) { + FString NewLabel; + + TArray> SelectedItems; + LabelTreeView->GetSelectedItems(SelectedItems); + for (TSharedPtr Item : SelectedItems) + { + if (!NewLabel.IsEmpty()) + { + NewLabel += TEXT(" "); + } + + if (!Item->Label.IsEmpty()) + { + NewLabel += FString(TEXT("label:")) + Item->Label; + } + } + OnSelectionChanged.ExecuteIfBound( InItem.IsValid() - ? InItem->Label + ? NewLabel : FString(), SelectInfo ); diff --git a/Engine/Source/Editor/Sequencer/Private/Sequencer.cpp b/Engine/Source/Editor/Sequencer/Private/Sequencer.cpp index 920ce68df832..440652a8c6b8 100644 --- a/Engine/Source/Editor/Sequencer/Private/Sequencer.cpp +++ b/Engine/Source/Editor/Sequencer/Private/Sequencer.cpp @@ -38,6 +38,7 @@ #include "ISequencerSection.h" #include "MovieSceneSequenceInstance.h" #include "IKeyArea.h" +#include "ISettingsModule.h" #include "IDetailsView.h" #include "SnappingUtils.h" #include "GenericCommands.h" @@ -127,6 +128,15 @@ void FSequencer::InitSequencer(const FSequencerInitParams& InitParams, const TSh Settings = USequencerSettingsContainer::GetOrCreate(*InitParams.ViewParams.UniqueName); + if (ISettingsModule* SettingsModule = FModuleManager::GetModulePtr("Settings")) + { + FName SettingsSectionName = *Settings->GetName(); + FText SettingsDisplayName = FText::FromString(FName::NameToDisplayString(*Settings->GetName(), false)); + FText SettingsDescription = FText::FromString("Configure the look and feel of the " + FName::NameToDisplayString(*Settings->GetName(), false)); + + SettingsModule->RegisterSettings("Editor", "ContentEditors", SettingsSectionName, SettingsDisplayName, SettingsDescription, Settings); + } + ToolkitHost = InitParams.ToolkitHost; ScrubPosition = InitParams.ViewParams.InitialScrubPosition; @@ -227,6 +237,7 @@ FSequencer::FSequencer() , bPerspectiveViewportCameraCutEnabled( false ) , bIsEditingWithinLevelEditor( false ) , bNeedTreeRefresh( false ) + , bNeedInstanceRefresh( false ) , StoredPlaybackState( EMovieScenePlayerStatus::Stopped ) , bWasClosed( false ) , NodeTree( MakeShareable( new FSequencerNodeTree( *this ) ) ) @@ -295,6 +306,12 @@ void FSequencer::Close() { GLevelEditorModeTools().DeactivateMode(FSequencerEdMode::EM_SequencerMode); } + + if (ISettingsModule* SettingsModule = FModuleManager::GetModulePtr("Settings")) + { + FName SettingsSectionName = *Settings->GetName(); + SettingsModule->UnregisterSettings("Editor", "ContentEditors", SettingsSectionName); + } } if (bIsEditingWithinLevelEditor) @@ -316,13 +333,17 @@ void FSequencer::Tick(float InDeltaTime) { Selection.Tick(); + if ( bNeedInstanceRefresh ) + { + // @todo - Sequencer Will be called too often + UpdateRuntimeInstances(); + bNeedInstanceRefresh = false; + } + if (bNeedTreeRefresh) { SelectionPreview.Empty(); - // @todo - Sequencer Will be called too often - UpdateRuntimeInstances(); - SequencerWidget->UpdateLayoutTree(); bNeedTreeRefresh = false; @@ -931,6 +952,7 @@ void FSequencer::NotifyMovieSceneDataChanged() StoredPlaybackState = GetPlaybackStatus(); SetPlaybackStatus(EMovieScenePlayerStatus::Stopped); bNeedTreeRefresh = true; + bNeedInstanceRefresh = true; UpdatePlaybackRange(); } @@ -1256,7 +1278,7 @@ float FSequencer::GetGlobalTime() const } -void FSequencer::SetGlobalTime( float NewTime, ESnapTimeMode SnapTimeMode ) +void FSequencer::SetGlobalTime( float NewTime, ESnapTimeMode SnapTimeMode, bool bLooped ) { if (IsAutoScrollEnabled()) { @@ -1274,11 +1296,11 @@ void FSequencer::SetGlobalTime( float NewTime, ESnapTimeMode SnapTimeMode ) } } - SetGlobalTimeDirectly(NewTime, SnapTimeMode); + SetGlobalTimeDirectly(NewTime, SnapTimeMode, bLooped); } -void FSequencer::SetGlobalTimeDirectly( float NewTime, ESnapTimeMode SnapTimeMode ) +void FSequencer::SetGlobalTimeDirectly( float NewTime, ESnapTimeMode SnapTimeMode, bool bLooped ) { float LastTime = ScrubPosition; @@ -1296,6 +1318,7 @@ void FSequencer::SetGlobalTimeDirectly( float NewTime, ESnapTimeMode SnapTimeMod ScrubPosition = NewTime; EMovieSceneUpdateData UpdateData(NewTime, LastTime); + UpdateData.bLooped = bLooped; SequenceInstanceStack.Top()->Update(UpdateData, *this); // Ensure any relevant spawned objects are cleaned up if we're playing back the master sequence @@ -2301,6 +2324,7 @@ bool FSequencer::IsLooping() const void FSequencer::SetGlobalTimeLooped(float InTime) { + bool bLooped = false; if (Settings->IsLooping()) { const UMovieSceneSequence* FocusedSequence = GetFocusedMovieSceneSequence(); @@ -2308,7 +2332,8 @@ void FSequencer::SetGlobalTimeLooped(float InTime) { if (InTime > FocusedSequence->GetMovieScene()->GetPlaybackRange().GetUpperBoundValue()) { - InTime -= FocusedSequence->GetMovieScene()->GetPlaybackRange().Size(); + InTime = FocusedSequence->GetMovieScene()->GetPlaybackRange().GetLowerBoundValue(); + bLooped = true; } } } @@ -2345,7 +2370,7 @@ void FSequencer::SetGlobalTimeLooped(float InTime) } } - SetGlobalTime(InTime); + SetGlobalTime(InTime, ESnapTimeMode::STM_None, bLooped); } @@ -3051,12 +3076,12 @@ void FSequencer::OnMapOpened(const FString& Filename, bool bLoadAsTemplate) void FSequencer::OnLevelAdded(ULevel* InLevel, UWorld* InWorld) { - NotifyMovieSceneDataChanged(); + bNeedInstanceRefresh = true; } void FSequencer::OnLevelRemoved(ULevel* InLevel, UWorld* InWorld) { - NotifyMovieSceneDataChanged(); + bNeedInstanceRefresh = true; } void FSequencer::OnNewActorsDropped(const TArray& DroppedObjects, const TArray& DroppedActors) @@ -3088,6 +3113,8 @@ void FSequencer::OnNewActorsDropped(const TArray& DroppedObjects, cons FGuid PossessableGuid = CreateBinding(*NewActor, NewActor->GetActorLabel()); FGuid NewGuid = PossessableGuid; + OnActorAddedToSequencerEvent.Broadcast(NewActor, PossessableGuid); + if (bAddSpawnable) { FMovieSceneSpawnable* Spawnable = ConvertToSpawnableInternal(PossessableGuid); @@ -3105,12 +3132,6 @@ void FSequencer::OnNewActorsDropped(const TArray& DroppedObjects, cons NewGuid = Spawnable->GetGuid(); NewActor = SpawnedActor; } - else - { - UpdateRuntimeInstances(); - - OnActorAddedToSequencerEvent.Broadcast(NewActor, PossessableGuid); - } if (bCreateAndAttachCamera) { @@ -3129,6 +3150,8 @@ void FSequencer::OnNewActorsDropped(const TArray& DroppedObjects, cons NewCamera->SetActorRotation(FRotator(0.f, -90.f, 0.f)); } + OnActorAddedToSequencerEvent.Broadcast(NewCamera, NewCameraGuid); + if (bAddSpawnable) { FMovieSceneSpawnable* Spawnable = ConvertToSpawnableInternal(NewCameraGuid); @@ -3146,8 +3169,6 @@ void FSequencer::OnNewActorsDropped(const TArray& DroppedObjects, cons } else { - OnActorAddedToSequencerEvent.Broadcast(NewCamera, NewCameraGuid); - // Parent it NewCamera->AttachToActor(NewActor, FAttachmentTransformRules::KeepRelativeTransform); } diff --git a/Engine/Source/Editor/Sequencer/Private/Sequencer.h b/Engine/Source/Editor/Sequencer/Private/Sequencer.h index d30eba9ad165..7999ea20183d 100644 --- a/Engine/Source/Editor/Sequencer/Private/Sequencer.h +++ b/Engine/Source/Editor/Sequencer/Private/Sequencer.h @@ -500,8 +500,8 @@ public: virtual bool IsRecordingLive() const override; virtual float GetCurrentLocalTime(UMovieSceneSequence& InMovieSceneSequence) override; virtual float GetGlobalTime() const override; - virtual void SetGlobalTime(float Time, ESnapTimeMode SnapTimeMode = ESnapTimeMode::STM_None) override; - virtual void SetGlobalTimeDirectly(float Time, ESnapTimeMode SnapTimeMode = ESnapTimeMode::STM_None) override; + virtual void SetGlobalTime(float Time, ESnapTimeMode SnapTimeMode = ESnapTimeMode::STM_None, bool bLooped = false) override; + virtual void SetGlobalTimeDirectly(float Time, ESnapTimeMode SnapTimeMode = ESnapTimeMode::STM_None, bool bLooped = false) override; virtual void SetPerspectiveViewportPossessionEnabled(bool bEnabled) override; virtual void SetPerspectiveViewportCameraCutEnabled(bool bEnabled) override; virtual void EnterSilentMode() override { ++SilentModeCount; } @@ -870,6 +870,9 @@ private: the MovieScene data can change many times per frame.) */ bool bNeedTreeRefresh; + /** When true, the runtime instances need to be updated next frame. */ + bool bNeedInstanceRefresh; + /** Stores the playback status to be restored on refresh. */ EMovieScenePlayerStatus::Type StoredPlaybackState; diff --git a/Engine/Source/Editor/Sequencer/Private/SequencerNodeTree.cpp b/Engine/Source/Editor/Sequencer/Private/SequencerNodeTree.cpp index fc5c33db0019..590b1a672f02 100644 --- a/Engine/Source/Editor/Sequencer/Private/SequencerNodeTree.cpp +++ b/Engine/Source/Editor/Sequencer/Private/SequencerNodeTree.cpp @@ -468,33 +468,51 @@ const TSharedPtr& FSequencerNodeTree::GetHoveredNode() co return HoveredNode; } +/* + * Add node as filtered and include any parent folders + */ +static void AddFilteredNode(const TSharedRef& StartNode, TSet>& OutFilteredNodes) +{ + OutFilteredNodes.Add(StartNode); + + // Gather parent folders up the chain + TSharedPtr ParentNode = StartNode->GetParent(); + while (ParentNode.IsValid() && ParentNode.Get()->GetType() == ESequencerNode::Folder) + { + OutFilteredNodes.Add(ParentNode.ToSharedRef()); + ParentNode = ParentNode->GetParent(); + } +} + /** * Recursively filters nodes * * @param StartNode The node to start from * @param FilterStrings The filter strings which need to be matched * @param OutFilteredNodes The list of all filtered nodes + * @return Whether the text filter was passed */ static bool FilterNodesRecursive( FSequencer& Sequencer, const TSharedRef& StartNode, const TArray& FilterStrings, TSet>& OutFilteredNodes ) { - // assume the filter is acceptable - bool PassedTextFilter = true; - - // check each string in the filter strings list against + // check labels - only one of the labels needs to match + bool bMatchedLabel = false; + bool bObjectHasLabels = false; for (const FString& String : FilterStrings) { if (String.StartsWith(TEXT("label:"))) - { + { if (!StartNode->GetParent().IsValid() && (String.Len() > 6)) { if (StartNode->GetType() == ESequencerNode::Object) { + bObjectHasLabels = true; auto ObjectBindingNode = StaticCastSharedRef(StartNode); auto Labels = Sequencer.GetLabelManager().GetObjectLabels(ObjectBindingNode->GetObjectBinding()); - if ((Labels == nullptr) || !Labels->Strings.Contains(String.RightChop(6))) + if (Labels != nullptr && Labels->Strings.Contains(String.RightChop(6))) { - return false; + bMatchedLabel = true; + break; } } else @@ -503,12 +521,20 @@ static bool FilterNodesRecursive( FSequencer& Sequencer, const TSharedRefGetDisplayName().ToString().Contains(String)) - { - PassedTextFilter = false; - } + } - if (!PassedTextFilter) + if (bObjectHasLabels && !bMatchedLabel) + { + return false; + } + + // assume the filter is acceptable + bool bPassedTextFilter = true; + + // check each string in the filter strings list against + for (const FString& String : FilterStrings) + { + if (!String.StartsWith(TEXT("label:")) && !StartNode->GetDisplayName().ToString().Contains(String)) { break; } @@ -517,10 +543,11 @@ static bool FilterNodesRecursive( FSequencer& Sequencer, const TSharedRef AutoKeyMode; - UPROPERTY( config ) + UPROPERTY( config, EditAnywhere, Category=Keyframing ) bool bKeyAllEnabled; - UPROPERTY( config ) + UPROPERTY( config, EditAnywhere, Category=Keyframing ) bool bKeyInterpPropertiesOnly; - UPROPERTY( config ) + UPROPERTY( config, EditAnywhere, Category=Keyframing ) TEnumAsByte KeyInterpolation; - UPROPERTY( config ) + UPROPERTY( config, EditAnywhere, Category=General ) TEnumAsByte SpawnPosition; - UPROPERTY( config ) + UPROPERTY( config, EditAnywhere, Category=Timeline ) bool bShowFrameNumbers; - UPROPERTY( config ) + UPROPERTY( config, EditAnywhere, Category=Timeline ) bool bShowRangeSlider; - UPROPERTY( config ) + UPROPERTY( config, EditAnywhere, Category=Snapping ) bool bIsSnapEnabled; - UPROPERTY( config ) + UPROPERTY( config, EditAnywhere, Category=Snapping ) float TimeSnapInterval; - UPROPERTY( config ) + UPROPERTY( config, EditAnywhere, Category=Snapping ) bool bSnapKeyTimesToInterval; - UPROPERTY( config ) + UPROPERTY( config, EditAnywhere, Category=Snapping ) bool bSnapKeyTimesToKeys; - UPROPERTY( config ) + UPROPERTY( config, EditAnywhere, Category=Snapping ) bool bSnapSectionTimesToInterval; - UPROPERTY( config ) + UPROPERTY( config, EditAnywhere, Category=Snapping ) bool bSnapSectionTimesToSections; - UPROPERTY( config ) + UPROPERTY( config, EditAnywhere, Category=Snapping ) bool bSnapPlayTimeToKeys; - UPROPERTY( config ) + UPROPERTY( config, EditAnywhere, Category=Snapping ) bool bSnapPlayTimeToInterval; - UPROPERTY( config ) + UPROPERTY( config, EditAnywhere, Category=Snapping ) bool bSnapPlayTimeToDraggedKey; - UPROPERTY( config ) + UPROPERTY( config, EditAnywhere, Category=Snapping ) bool bFixedTimeStepPlayback; - UPROPERTY( config ) + UPROPERTY( config, EditAnywhere, Category=Snapping ) float CurveValueSnapInterval; - UPROPERTY( config ) + UPROPERTY( config, EditAnywhere, Category=Snapping ) bool bSnapCurveValueToInterval; - UPROPERTY( config ) - bool bDetailsViewVisible; - - UPROPERTY( config ) + UPROPERTY( config, EditAnywhere, Category=General ) bool bLabelBrowserVisible; - UPROPERTY( config ) + UPROPERTY( config, EditAnywhere, Category=Timeline ) + TEnumAsByte ZoomPosition; + + UPROPERTY( config, EditAnywhere, Category=Timeline ) bool bAutoScrollEnabled; - UPROPERTY( config ) + UPROPERTY( config, EditAnywhere, Category=CurveEditor ) bool bShowCurveEditor; - UPROPERTY( config ) + UPROPERTY( config, EditAnywhere, Category=CurveEditor ) bool bShowCurveEditorCurveToolTips; - UPROPERTY( config ) + UPROPERTY( config, EditAnywhere, Category=CurveEditor ) bool bLinkCurveEditorTimeRange; UPROPERTY( config ) bool bLooping; - UPROPERTY( config ) + UPROPERTY( config, EditAnywhere, Category=Timeline ) bool bKeepCursorInPlayRange; - UPROPERTY( config ) + UPROPERTY( config, EditAnywhere, Category=Timeline ) bool bKeepPlayRangeInSectionBounds; - UPROPERTY( config ) + UPROPERTY( config, EditAnywhere, Category=Timeline ) uint8 ZeroPadFrames; - UPROPERTY( config ) + UPROPERTY( config, EditAnywhere, Category=Timeline ) bool bShowCombinedKeyframes; - UPROPERTY( config ) + UPROPERTY( config, EditAnywhere, Category=Timeline ) bool bInfiniteKeyAreas; - UPROPERTY( config ) + UPROPERTY( config, EditAnywhere, Category=Timeline ) bool bShowChannelColors; UPROPERTY( config ) diff --git a/Engine/Source/Editor/Sequencer/Private/SequencerTimeSliderController.cpp b/Engine/Source/Editor/Sequencer/Private/SequencerTimeSliderController.cpp index 4863b54ff69b..59f9b3bbdf40 100644 --- a/Engine/Source/Editor/Sequencer/Private/SequencerTimeSliderController.cpp +++ b/Engine/Source/Editor/Sequencer/Private/SequencerTimeSliderController.cpp @@ -498,7 +498,7 @@ FReply FSequencerTimeSliderController::OnMouseButtonDown( SWidget& WidgetOwner, DistanceDragged = 0; FScrubRangeToScreen RangeToScreen( TimeSliderArgs.ViewRange.Get(), MyGeometry.Size ); - MouseDownRange[0] = RangeToScreen.LocalXToInput(MyGeometry.AbsoluteToLocal(MouseEvent.GetLastScreenSpacePosition()).X); + MouseDownRange[0] = RangeToScreen.LocalXToInput(MyGeometry.AbsoluteToLocal(MouseEvent.GetScreenSpacePosition()).X); MouseDownRange[1] = MouseDownRange[0]; if ( bHandleLeftMouseButton ) @@ -696,13 +696,14 @@ FReply FSequencerTimeSliderController::OnMouseMove( SWidget& WidgetOwner, const TRange PlaybackRange = TimeSliderArgs.PlaybackRange.Get(); float LocalMouseDownPos = RangeToScreen.InputToLocalX(MouseDownRange[0]); - if (HitTestScrubberEnd(RangeToScreen, SelectionRange, LocalMouseDownPos, ScrubPosition)) + // Disable selection range test if it's empty so that the playback range scrubbing gets priority + if (!SelectionRange.IsEmpty() && HitTestScrubberEnd(RangeToScreen, SelectionRange, LocalMouseDownPos, ScrubPosition)) { // selection range end scrubber MouseDragType = DRAG_SELECTION_END; TimeSliderArgs.OnSelectionRangeBeginDrag.ExecuteIfBound(); } - else if (HitTestScrubberStart(RangeToScreen, SelectionRange, LocalMouseDownPos, ScrubPosition)) + else if (!SelectionRange.IsEmpty() && HitTestScrubberStart(RangeToScreen, SelectionRange, LocalMouseDownPos, ScrubPosition)) { // selection range start scrubber MouseDragType = DRAG_SELECTION_START; @@ -823,9 +824,22 @@ FReply FSequencerTimeSliderController::OnMouseWheel( SWidget& WidgetOwner, const { TOptional> NewTargetRange; - float MouseFractionX = MyGeometry.AbsoluteToLocal(MouseEvent.GetScreenSpacePosition()).X / MyGeometry.GetLocalSize().X; if ( TimeSliderArgs.AllowZoom && MouseEvent.IsControlDown() ) { + float MouseFractionX = MyGeometry.AbsoluteToLocal(MouseEvent.GetScreenSpacePosition()).X / MyGeometry.GetLocalSize().X; + + // If zooming on the current time, adjust mouse fractionX + if (TimeSliderArgs.Settings->GetZoomPosition() == ESequencerZoomPosition::SZP_CurrentTime) + { + const float ScrubPosition = TimeSliderArgs.ScrubPosition.Get(); + if (TimeSliderArgs.ViewRange.Get().Contains(ScrubPosition)) + { + FScrubRangeToScreen RangeToScreen(TimeSliderArgs.ViewRange.Get(), MyGeometry.Size); + float TimePosition = RangeToScreen.InputToLocalX(ScrubPosition); + MouseFractionX = TimePosition / MyGeometry.GetLocalSize().X; + } + } + const float ZoomDelta = -0.2f * MouseEvent.GetWheelDelta(); if (ZoomByDelta(ZoomDelta, MouseFractionX)) { @@ -856,8 +870,8 @@ FCursorReply FSequencerTimeSliderController::OnCursorQuery( TSharedRef& PlaybackRange, float LocalHitPositionX, float ScrubPosition) const { - static float BrushSizeInStateUnits = 6.f, DragToleranceSlateUnits = 2.f; + static float BrushSizeInStateUnits = 6.f, DragToleranceSlateUnits = 2.f, MouseTolerance = 2.f; float LocalPlaybackStartPos = RangeToScreen.InputToLocalX(PlaybackRange.GetLowerBoundValue()); // We favor hit testing the scrub bar over hit testing the playback range bounds @@ -1101,13 +1115,13 @@ bool FSequencerTimeSliderController::HitTestScrubberStart(const FScrubRangeToScr } // Hit test against the brush region to the right of the playback start position, +/- DragToleranceSlateUnits - return LocalHitPositionX >= LocalPlaybackStartPos - DragToleranceSlateUnits && - LocalHitPositionX <= LocalPlaybackStartPos + BrushSizeInStateUnits + DragToleranceSlateUnits; + return LocalHitPositionX >= LocalPlaybackStartPos - MouseTolerance - DragToleranceSlateUnits && + LocalHitPositionX <= LocalPlaybackStartPos + MouseTolerance + BrushSizeInStateUnits + DragToleranceSlateUnits; } bool FSequencerTimeSliderController::HitTestScrubberEnd(const FScrubRangeToScreen& RangeToScreen, const TRange& PlaybackRange, float LocalHitPositionX, float ScrubPosition) const { - static float BrushSizeInStateUnits = 6.f, DragToleranceSlateUnits = 2.f; + static float BrushSizeInStateUnits = 6.f, DragToleranceSlateUnits = 2.f, MouseTolerance = 2.f; float LocalPlaybackEndPos = RangeToScreen.InputToLocalX(PlaybackRange.GetUpperBoundValue()); // We favor hit testing the scrub bar over hit testing the playback range bounds @@ -1117,8 +1131,8 @@ bool FSequencerTimeSliderController::HitTestScrubberEnd(const FScrubRangeToScree } // Hit test against the brush region to the left of the playback end position, +/- DragToleranceSlateUnits - return LocalHitPositionX >= LocalPlaybackEndPos - BrushSizeInStateUnits - DragToleranceSlateUnits && - LocalHitPositionX <= LocalPlaybackEndPos + DragToleranceSlateUnits; + return LocalHitPositionX >= LocalPlaybackEndPos - MouseTolerance - BrushSizeInStateUnits - DragToleranceSlateUnits && + LocalHitPositionX <= LocalPlaybackEndPos + MouseTolerance + DragToleranceSlateUnits; } void FSequencerTimeSliderController::SetPlaybackRangeStart(float NewStart) diff --git a/Engine/Source/Editor/Sequencer/Public/ISequencer.h b/Engine/Source/Editor/Sequencer/Public/ISequencer.h index 8ccd12e91e62..80426ec0009f 100644 --- a/Engine/Source/Editor/Sequencer/Public/ISequencer.h +++ b/Engine/Source/Editor/Sequencer/Public/ISequencer.h @@ -192,12 +192,13 @@ public: * * @param Time The global time to set. * @param SnapTimeMode The type of time snapping allowed. + * @param bLooped Whether the time has been looped * @see GetGlobalTime */ - virtual void SetGlobalTime(float Time, ESnapTimeMode SnapTimeMode = ESnapTimeMode::STM_None) = 0; + virtual void SetGlobalTime(float Time, ESnapTimeMode SnapTimeMode = ESnapTimeMode::STM_None, bool bLooped = false) = 0; /** Set the global time directly, without performing any auto-scroll */ - virtual void SetGlobalTimeDirectly(float Time, ESnapTimeMode SnapTimeMode = ESnapTimeMode::STM_None) = 0; + virtual void SetGlobalTimeDirectly(float Time, ESnapTimeMode SnapTimeMode = ESnapTimeMode::STM_None, bool bLooped = false) = 0; /** @return The current view range */ virtual FAnimatedRange GetViewRange() const diff --git a/Engine/Source/Editor/UMGEditor/Private/AssetTypeActions_WidgetBlueprint.h b/Engine/Source/Editor/UMGEditor/Private/AssetTypeActions_WidgetBlueprint.h index 732851e28242..d126683f0ad8 100644 --- a/Engine/Source/Editor/UMGEditor/Private/AssetTypeActions_WidgetBlueprint.h +++ b/Engine/Source/Editor/UMGEditor/Private/AssetTypeActions_WidgetBlueprint.h @@ -12,6 +12,7 @@ public: virtual UClass* GetSupportedClass() const override; virtual void OpenAssetEditor(const TArray& InObjects, TSharedPtr EditWithinLevelEditor = TSharedPtr()) override; virtual uint32 GetCategories() override { return EAssetTypeCategories::UI; } + virtual bool CanLocalize() const override { return false; } virtual void PerformAssetDiff(UObject* Asset1, UObject* Asset2, const struct FRevisionInfo& OldRevision, const struct FRevisionInfo& NewRevision) const override; virtual FText GetAssetDescription( const FAssetData& AssetData ) const override; // End IAssetTypeActions Implementation diff --git a/Engine/Source/Editor/UMGEditor/Private/WidgetBlueprintEditorUtils.cpp b/Engine/Source/Editor/UMGEditor/Private/WidgetBlueprintEditorUtils.cpp index c1c73d8c69be..bcd46b33a0a3 100644 --- a/Engine/Source/Editor/UMGEditor/Private/WidgetBlueprintEditorUtils.cpp +++ b/Engine/Source/Editor/UMGEditor/Private/WidgetBlueprintEditorUtils.cpp @@ -35,7 +35,7 @@ public: // FCustomizableTextObjectFactory implementation - virtual bool CanCreateClass(UClass* ObjectClass) const override + virtual bool CanCreateClass(UClass* ObjectClass, bool& bOmitSubObjs) const override { const bool bIsWidget = ObjectClass->IsChildOf(UWidget::StaticClass()); const bool bIsSlot = ObjectClass->IsChildOf(UPanelSlot::StaticClass()); diff --git a/Engine/Source/Editor/UnrealEd/Classes/Editor/EditorEngine.h b/Engine/Source/Editor/UnrealEd/Classes/Editor/EditorEngine.h index bcc419d081f4..1cfdd7ba6eab 100644 --- a/Engine/Source/Editor/UnrealEd/Classes/Editor/EditorEngine.h +++ b/Engine/Source/Editor/UnrealEd/Classes/Editor/EditorEngine.h @@ -561,6 +561,9 @@ public: protected: + /** Count of how many PIE instances are waiting to log in */ + int32 PIEInstancesToLogInCount; + /* These are parameters that we need to cache for late joining */ FString ServerPrefix; int32 PIEInstance; @@ -2485,6 +2488,9 @@ private: /** Above function but called a frame later, to stop PIE login from happening from a network callback */ virtual void OnLoginPIEComplete_Deferred(int32 LocalUserNum, bool bWasSuccessful, FString ErrorString, FPieLoginStruct DataStruct); + /** Called when all PIE instances have been successfully logged in */ + virtual void OnLoginPIEAllComplete(); + public: /** * Continue the creation of a single PIE world after a login was successful @@ -2536,6 +2542,11 @@ private: */ void OnSwitchWorldsForPIE( bool bSwitchToPieWorld ); + /** + * Gives focus to the server or first PIE client viewport + */ + void GiveFocusToFirstClientPIEViewport(); + public: /** * Spawns a PlayFromHere playerstart in the given world diff --git a/Engine/Source/Editor/UnrealEd/Classes/MaterialGraph/MaterialGraphNode.h b/Engine/Source/Editor/UnrealEd/Classes/MaterialGraph/MaterialGraphNode.h index fd115159a594..8b580f3f962e 100644 --- a/Engine/Source/Editor/UnrealEd/Classes/MaterialGraph/MaterialGraphNode.h +++ b/Engine/Source/Editor/UnrealEd/Classes/MaterialGraph/MaterialGraphNode.h @@ -2,6 +2,8 @@ #pragma once +#include "MaterialGraph.h" +#include "MaterialGraphNode_Base.h" #include "MaterialGraphNode.generated.h" UCLASS(MinimalAPI) diff --git a/Engine/Source/Editor/UnrealEd/Classes/Settings/EditorLoadingSavingSettings.h b/Engine/Source/Editor/UnrealEd/Classes/Settings/EditorLoadingSavingSettings.h index 5f6ef567956e..d87bd4969f7a 100644 --- a/Engine/Source/Editor/UnrealEd/Classes/Settings/EditorLoadingSavingSettings.h +++ b/Engine/Source/Editor/UnrealEd/Classes/Settings/EditorLoadingSavingSettings.h @@ -86,16 +86,10 @@ public: UPROPERTY(EditAnywhere, config, Category=Startup) uint32 bRestoreOpenAssetTabsOnRestart:1; -public: - - /** Check that the current source control settings will play nicely with the auto-reimport feature */ - void CheckSourceControlCompatability(); - private: - /** true when CheckSourceControlCompatability is enabled */ UPROPERTY(config) - bool bEnableSourceControlCompatabilityCheck; + bool bEnableSourceControlCompatabilityCheck_DEPRECATED; public: diff --git a/Engine/Source/Editor/UnrealEd/Private/Animation/EditorCompositeSection.cpp b/Engine/Source/Editor/UnrealEd/Private/Animation/EditorCompositeSection.cpp index c7f939c2352b..aa246c93c5a4 100644 --- a/Engine/Source/Editor/UnrealEd/Private/Animation/EditorCompositeSection.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/Animation/EditorCompositeSection.cpp @@ -5,7 +5,7 @@ =============================================================================*/ #include "UnrealEd.h" - +#include "Animation/AnimMetaData.h" UEditorCompositeSection::UEditorCompositeSection(const FObjectInitializer& ObjectInitializer) @@ -15,6 +15,26 @@ UEditorCompositeSection::UEditorCompositeSection(const FObjectInitializer& Objec SectionIndex = INDEX_NONE; } +// since meta data is instanced, they have to copied manually with correct Outer +// when we move between editor composite section and montage composite section +void CopyMetaData(FCompositeSection& Source, FCompositeSection& Dest, UObject* DestOuter) +{ + const int32 TotalMetaData = Source.MetaData.Num(); + Dest.MetaData.Reset(TotalMetaData); + Dest.MetaData.AddZeroed(TotalMetaData); + + for (int32 Idx = 0; Idx < TotalMetaData; ++Idx) + { + UAnimMetaData* SourceMetaData = Source.MetaData[Idx]; + if (SourceMetaData) + { + TSubclassOf SourceMetaDataClass = SourceMetaData->GetClass(); + UAnimMetaData* NewMetaData = NewObject(DestOuter, SourceMetaDataClass, NAME_None, RF_NoFlags, SourceMetaData); + Dest.MetaData[Idx] = NewMetaData; + } + } +} + void UEditorCompositeSection::InitSection(int SectionIndexIn) { SectionIndex = SectionIndexIn; @@ -23,6 +43,7 @@ void UEditorCompositeSection::InitSection(int SectionIndexIn) if(Montage->CompositeSections.IsValidIndex(SectionIndex)) { CompositeSection = Montage->CompositeSections[SectionIndex]; + CopyMetaData(Montage->CompositeSections[SectionIndex], CompositeSection, this); } } } @@ -34,9 +55,11 @@ bool UEditorCompositeSection::ApplyChangesToMontage() { CompositeSection.OnChanged(CompositeSection.GetTime()); Montage->CompositeSections[SectionIndex] = CompositeSection; + CopyMetaData(CompositeSection, Montage->CompositeSections[SectionIndex], Montage); return true; } } return false; } + diff --git a/Engine/Source/Editor/UnrealEd/Private/EdGraphUtilities.cpp b/Engine/Source/Editor/UnrealEd/Private/EdGraphUtilities.cpp index 60cf6cd403dc..00a1b71b7fdc 100644 --- a/Engine/Source/Editor/UnrealEd/Private/EdGraphUtilities.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/EdGraphUtilities.cpp @@ -28,10 +28,14 @@ public: } protected: - virtual bool CanCreateClass(UClass* ObjectClass) const override + virtual bool CanCreateClass(UClass* ObjectClass, bool& bOmitSubObjs) const override { if (const UEdGraphNode* DefaultNode = Cast(ObjectClass->GetDefaultObject())) { + // if the root node can't be created, don't continue to check sub- + // objects (for like collapsed graphs, or anim state-machine nodes) + bOmitSubObjs = true; + if (DefaultNode->CanDuplicateNode()) { if (DestinationGraph != NULL) diff --git a/Engine/Source/Editor/UnrealEd/Private/EditorEngine.cpp b/Engine/Source/Editor/UnrealEd/Private/EditorEngine.cpp index 1950c1ca6bfc..87439b380e5f 100644 --- a/Engine/Source/Editor/UnrealEd/Private/EditorEngine.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/EditorEngine.cpp @@ -4069,7 +4069,7 @@ void UEditorEngine::OnPostSaveWorld(uint32 SaveFlags, UWorld* World, uint32 Orig if ( MainFrameModule.GetMRUFavoritesList() ) { - MainFrameModule.GetMRUFavoritesList()->AddMRUItem( Filename ); + MainFrameModule.GetMRUFavoritesList()->AddMRUItem(WorldPackage->GetName()); } FEditorDirectories::Get().SetLastDirectory(ELastDirectory::UNR, FPaths::GetPath(Filename)); // Save path as default for next time. diff --git a/Engine/Source/Editor/UnrealEd/Private/EditorViewportClient.cpp b/Engine/Source/Editor/UnrealEd/Private/EditorViewportClient.cpp index 734cd32ab037..a6f19d7f3378 100644 --- a/Engine/Source/Editor/UnrealEd/Private/EditorViewportClient.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/EditorViewportClient.cpp @@ -3143,15 +3143,34 @@ void FEditorViewportClient::SetupViewForRendering( FSceneViewFamily& ViewFamily, FPixelInspectorModule* PixelInspectorModule = &FModuleManager::LoadModuleChecked(TEXT("PixelInspectorModule")); if (PixelInspectorModule != nullptr) { - View.bUsePixelInspector = PixelInspectorModule->IsPixelInspectorEnable(); - bool IsMouseInsideViewport = CurrentMousePos != FIntPoint(-1, -1); - if (View.bUsePixelInspector && IsMouseInsideViewport) + bool IsInspectorActive = PixelInspectorModule->IsPixelInspectorEnable(); + View.bUsePixelInspector = IsInspectorActive; + FIntPoint InspectViewportPos = FIntPoint(-1, -1); + if (IsInspectorActive) + { + if (CurrentMousePos == FIntPoint(-1, -1)) + { + uint32 CoordinateViewportId = 0; + PixelInspectorModule->GetCoordinatePosition(InspectViewportPos, CoordinateViewportId); + PixelInspectorModule->SetViewportInformation(View.State->GetViewKey(), Viewport->GetSizeXY()); + bool IsCoordinateInViewport = InspectViewportPos.X <= Viewport->GetSizeXY().X && InspectViewportPos.Y <= Viewport->GetSizeXY().Y; + IsInspectorActive = IsCoordinateInViewport && (CoordinateViewportId == View.State->GetViewKey()); + } + else + { + InspectViewportPos = CurrentMousePos; + PixelInspectorModule->SetViewportInformation(View.State->GetViewKey(), Viewport->GetSizeXY()); + PixelInspectorModule->SetCoordinatePosition(CurrentMousePos, false); + } + } + + if (IsInspectorActive) { // Ready to send a request FSceneInterface *SceneInterface = GetScene(); - PixelInspectorModule->CreatePixelInspectorRequest(CurrentMousePos, View.State->GetViewKey(), SceneInterface); + PixelInspectorModule->CreatePixelInspectorRequest(InspectViewportPos, View.State->GetViewKey(), SceneInterface); } - else if (!View.bUsePixelInspector && IsMouseInsideViewport) + else if (!View.bUsePixelInspector && CurrentMousePos != FIntPoint(-1, -1)) { //Track in case the user hit esc key to stop inspecting pixel PixelInspectorRealtimeManagement(this, true); diff --git a/Engine/Source/Editor/UnrealEd/Private/Factories/EditorFactories.cpp b/Engine/Source/Editor/UnrealEd/Private/Factories/EditorFactories.cpp index 0531046bc8cd..270a39e83382 100644 --- a/Engine/Source/Editor/UnrealEd/Private/Factories/EditorFactories.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/Factories/EditorFactories.cpp @@ -5273,17 +5273,37 @@ void FCustomizableTextObjectFactory::ProcessBuffer(UObject* InParent, EObjectFla FParse::Next( &Buffer ); + int32 NestedDepth = 0; + int32 OmittedOuterObj = 0; // zero signifies "nothing omitted" + FString StrLine; while( FParse::Line(&Buffer,StrLine) ) { const TCHAR* Str = *StrLine; if( GetBEGIN(&Str,TEXT("OBJECT")) ) { + ++NestedDepth; + if (OmittedOuterObj > 0) + { + if (NestedDepth > OmittedOuterObj) + { + continue; + } + ensure(OmittedOuterObj == NestedDepth); + // clear the omitted outer, we've parsed passed it + OmittedOuterObj = 0; + } + UClass* ObjClass; if( ParseObject( Str, TEXT("CLASS="), ObjClass, ANY_PACKAGE ) ) { - if (!CanCreateClass(ObjClass)) + bool bOmitSubObjects = false; + if (!CanCreateClass(ObjClass, bOmitSubObjects)) { + if (bOmitSubObjects) + { + OmittedOuterObj = NestedDepth; + } continue; } @@ -5343,6 +5363,10 @@ void FCustomizableTextObjectFactory::ProcessBuffer(UObject* InParent, EObjectFla NewObjects.Add(CreatedObject); } } + else if (GetEND(&Str, TEXT("OBJECT"))) + { + --NestedDepth; + } } // Apply the property text to each of the created objects @@ -5368,28 +5392,52 @@ bool FCustomizableTextObjectFactory::CanCreateObjectsFromText( const FString& Te FParse::Next( &Buffer ); + int32 NestedDepth = 0; + int32 OmittedOuterObj = 0; // zero signifies "nothing omitted" + FString StrLine; while( FParse::Line(&Buffer,StrLine) ) { const TCHAR* Str = *StrLine; if( GetBEGIN(&Str,TEXT("OBJECT")) ) { - UClass* ObjClass; - if( ParseObject( Str, TEXT("CLASS="), ObjClass, ANY_PACKAGE ) ) + ++NestedDepth; + if (OmittedOuterObj > 0) { - if(CanCreateClass(ObjClass)) + if (NestedDepth > OmittedOuterObj) + { + continue; + } + ensure(OmittedOuterObj == NestedDepth); + // clear the omitted outer, we've parsed passed it + OmittedOuterObj = 0; + } + + UClass* ObjClass; + if (ParseObject(Str, TEXT("CLASS="), ObjClass, ANY_PACKAGE)) + { + bool bOmitSubObjects = false;; + if (CanCreateClass(ObjClass, bOmitSubObjects)) { bCanCreate = true; break; } + else if (bOmitSubObjects) + { + OmittedOuterObj = NestedDepth; + } } } + else if ( GetEND(&Str, TEXT("OBJECT")) ) + { + --NestedDepth; + } } return bCanCreate; } /** Return true if the an object of type ObjectClass is allowed to be created; If false is returned, the object and subobjects will be ignored. */ -bool FCustomizableTextObjectFactory::CanCreateClass(UClass* ObjectClass) const +bool FCustomizableTextObjectFactory::CanCreateClass(UClass* ObjectClass, bool& bOmitSubObjs) const { return false; } diff --git a/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxFactory.cpp b/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxFactory.cpp index b8e0c6fe4455..5f897dc54348 100644 --- a/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxFactory.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxFactory.cpp @@ -167,8 +167,11 @@ UObject* UFbxFactory::FactoryCreateBinary // this one prints all messages that are stored in FFbxImporter UnFbx::FFbxImporter* FbxImporter = UnFbx::FFbxImporter::GetInstance(); UnFbx::FBXImportOptions* ImportOptions = FbxImporter->GetImportOptions(); - //Clean up the options - UnFbx::FBXImportOptions::ResetOptions(ImportOptions); + if (bShowOption) + { + //Clean up the options + UnFbx::FBXImportOptions::ResetOptions(ImportOptions); + } UnFbx::FFbxLoggerSetter Logger(FbxImporter); diff --git a/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxMainImport.cpp b/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxMainImport.cpp index 8178662ef03a..6a05a4aafdc5 100644 --- a/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxMainImport.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxMainImport.cpp @@ -1801,9 +1801,7 @@ void FFbxImporter::RecursiveFindRigidMesh(FbxNode* Node, TArray< TArrayGetChildCount(); ++ChildIndex) { - FbxNode* MeshNode = FindLODGroupNode(Node, ChildIndex); - if(MeshNode != nullptr) - RecursiveFindRigidMesh(MeshNode, outSkelMeshArray, SkeletonArray, ExpandLOD); + RecursiveFindRigidMesh(Node->GetChild(ChildIndex), outSkelMeshArray, SkeletonArray, ExpandLOD); } } } diff --git a/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxSceneImportFactory.cpp b/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxSceneImportFactory.cpp index 2993f0b5a84c..80565c40859c 100644 --- a/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxSceneImportFactory.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxSceneImportFactory.cpp @@ -1067,7 +1067,7 @@ USceneComponent *CreateLightComponent(AActor *ParentActor, TSharedPtr(ParentActor, *(LightInfo->Name)); PointLightComponent->SetAttenuationRadius(LightInfo->EnableFarAttenuation ? LightInfo->FarAttenuationEnd : 16384.0f); LightComponent = static_cast(PointLightComponent); - LightComponent->SetIntensity(LightInfo->Intensity); + LightComponent->SetIntensity(LightComponent->Intensity * LightInfo->Intensity / 100.0f); } break; case 1: @@ -1075,7 +1075,8 @@ USceneComponent *CreateLightComponent(AActor *ParentActor, TSharedPtr(ParentActor, *(LightInfo->Name)); LightComponent = static_cast(DirectionalLightComponent); - LightComponent->SetIntensity(LightInfo->Intensity/100); //In unreal this is a ratio not a lumen value + //We cannot convert fbx value to unreal value so we kept the default object value + LightComponent->SetIntensity(LightComponent->Intensity * LightInfo->Intensity / 100.0f); } break; case 2: @@ -1086,7 +1087,8 @@ USceneComponent *CreateLightComponent(AActor *ParentActor, TSharedPtrSetOuterConeAngle(LightInfo->OuterAngle/2.0f); SpotLightComponent->SetAttenuationRadius(LightInfo->EnableFarAttenuation ? LightInfo->FarAttenuationEnd : 16384.0f); LightComponent = static_cast(SpotLightComponent); - LightComponent->SetIntensity(LightInfo->Intensity); + + LightComponent->SetIntensity(LightComponent->Intensity * LightInfo->Intensity / 100.0f); } break; case 3: diff --git a/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxStaticMeshImport.cpp b/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxStaticMeshImport.cpp index e0783b3db062..7a6a3e1e9786 100644 --- a/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxStaticMeshImport.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxStaticMeshImport.cpp @@ -954,7 +954,7 @@ UStaticMesh* UnFbx::FFbxImporter::ImportStaticMeshAsSingle(UObject* InParent, TA // Parent package to place new meshes UPackage* Package = NULL; - if (InParent != nullptr && InParent->IsA(UPackage::StaticClass())) + if (ImportOptions->bImportScene && InParent != nullptr && InParent->IsA(UPackage::StaticClass())) { Package = StaticCast(InParent); } diff --git a/Engine/Source/Editor/UnrealEd/Private/FileHelpers.cpp b/Engine/Source/Editor/UnrealEd/Private/FileHelpers.cpp index 012e5d208d70..e20b9d48bcd9 100644 --- a/Engine/Source/Editor/UnrealEd/Private/FileHelpers.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/FileHelpers.cpp @@ -2175,7 +2175,7 @@ void FEditorFileUtils::LoadMap(const FString& InFilename, bool LoadAsTemplate, b FMainMRUFavoritesList* MRUFavoritesList = MainFrameModule.GetMRUFavoritesList(); if(MRUFavoritesList) { - MRUFavoritesList->AddMRUItem( *Filename ); + MRUFavoritesList->AddMRUItem(LongMapPackageName); } } diff --git a/Engine/Source/Editor/UnrealEd/Private/GroupActor.cpp b/Engine/Source/Editor/UnrealEd/Private/GroupActor.cpp index d556e210728e..fb8dd20f696e 100644 --- a/Engine/Source/Editor/UnrealEd/Private/GroupActor.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/GroupActor.cpp @@ -100,6 +100,21 @@ bool ActorHasParentInGroup(const TArray &GroupActors, const AActo return false; } +bool ActorHasParentInSelection(const AActor* Actor) +{ + check(Actor); + bool bHasParentInSelection = false; + AActor* ParentActor = Actor->GetAttachParentActor(); + while (ParentActor != NULL && !bHasParentInSelection) + { + if (ParentActor->IsSelected()) + { + bHasParentInSelection = true; + } + ParentActor = ParentActor->GetAttachParentActor(); + } + return bHasParentInSelection; +} void AGroupActor::GroupApplyDelta(FLevelEditorViewportClient* Viewport, const FVector& InDrag, const FRotator& InRot, const FVector& InScale ) { @@ -108,11 +123,11 @@ void AGroupActor::GroupApplyDelta(FLevelEditorViewportClient* Viewport, const FV { if( GroupActors[ActorIndex] != NULL ) { - // Check that we've not got a parent attachment within the group. - const bool canApplyDelta = !ActorHasParentInGroup(GroupActors, GroupActors[ActorIndex]); - if( canApplyDelta ) + // Check that we've not got a parent attachment within the group/selection + const bool bCanApplyDelta = !ActorHasParentInGroup(GroupActors, GroupActors[ActorIndex]) && !ActorHasParentInSelection(GroupActors[ActorIndex]); + if(bCanApplyDelta) { - Viewport->ApplyDeltaToActor( GroupActors[ActorIndex], InDrag, InRot, InScale ); + Viewport->ApplyDeltaToActor(GroupActors[ActorIndex], InDrag, InRot, InScale); } } } @@ -130,9 +145,9 @@ void AGroupActor::GroupApplyDelta(const FVector& InDrag, const FRotator& InRot, { for(int32 ActorIndex=0; ActorIndexApplyDeltaToActor( GroupActors[ActorIndex], true, &InDrag, &InRot, &InScale ); } diff --git a/Engine/Source/Editor/UnrealEd/Private/Kismet2/BlueprintEditorUtils.cpp b/Engine/Source/Editor/UnrealEd/Private/Kismet2/BlueprintEditorUtils.cpp index 69d3e7b32ef9..0b83dff1a286 100644 --- a/Engine/Source/Editor/UnrealEd/Private/Kismet2/BlueprintEditorUtils.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/Kismet2/BlueprintEditorUtils.cpp @@ -5149,14 +5149,28 @@ bool FBlueprintEditorUtils::IsVariableUsed(const UBlueprint* Blueprint, const FN TArray GraphNodes; CurrentGraph->GetNodesOfClass(GraphNodes); - for( TArray::TConstIterator NodeIt(GraphNodes); NodeIt; ++NodeIt ) + for (const UK2Node_Variable* CurrentNode : GraphNodes ) { - UK2Node_Variable* CurrentNode = *NodeIt; if(Name == CurrentNode->GetVarName()) { return true; } } + + // Also consider "used" if there's a GetClassDefaults node that exposes the variable as an output pin that's connected to something. + TArray ClassDefaultsNodes; + CurrentGraph->GetNodesOfClass(ClassDefaultsNodes); + for (const UK2Node_GetClassDefaults* ClassDefaultsNode : ClassDefaultsNodes) + { + if (ClassDefaultsNode->GetInputClass() == Blueprint->SkeletonGeneratedClass) + { + const UEdGraphPin* VarPin = ClassDefaultsNode->FindPin(Name.ToString()); + if (VarPin && VarPin->Direction == EGPD_Output && VarPin->LinkedTo.Num() > 0) + { + return true; + } + } + } } } return false; diff --git a/Engine/Source/Editor/UnrealEd/Private/Kismet2/ComponentEditorUtils.cpp b/Engine/Source/Editor/UnrealEd/Private/Kismet2/ComponentEditorUtils.cpp index e11aa98b3ae1..704353f46d17 100644 --- a/Engine/Source/Editor/UnrealEd/Private/Kismet2/ComponentEditorUtils.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/Kismet2/ComponentEditorUtils.cpp @@ -84,7 +84,7 @@ protected: // FCustomizableTextObjectFactory implementation - virtual bool CanCreateClass(UClass* ObjectClass) const override + virtual bool CanCreateClass(UClass* ObjectClass, bool& bOmitSubObjs) const override { // Only allow actor component types to be created return ObjectClass->IsChildOf(UActorComponent::StaticClass()); diff --git a/Engine/Source/Editor/UnrealEd/Private/MRUFavoritesList.cpp b/Engine/Source/Editor/UnrealEd/Private/MRUFavoritesList.cpp index be80aa25bf1c..34b8ba0c9dcd 100644 --- a/Engine/Source/Editor/UnrealEd/Private/MRUFavoritesList.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/MRUFavoritesList.cpp @@ -38,30 +38,31 @@ void FMainMRUFavoritesList::WriteToINI() const } /** - * Add a new file item to the favorites list + * Add a new item to the favorites list * - * @param Item Filename of the item to add to the favorites list + * @param Item Package name of the item to add to the favorites list */ void FMainMRUFavoritesList::AddFavoritesItem( const FString& Item ) { + check(FPackageName::IsValidLongPackageName(Item)); + // Only add the item if it isn't already a favorite! - const FString CleanedName = FPaths::ConvertRelativePathToFull(Item); - if ( !FavoriteItems.Contains( CleanedName ) ) + if ( !FavoriteItems.Contains( Item ) ) { - FavoriteItems.Insert( CleanedName, 0 ); + FavoriteItems.Insert( Item, 0 ); WriteToINI(); } } /** - * Remove a file from the favorites list + * Remove an item from the favorites list * - * @param Item Filename of the item to remove from the favorites list + * @param Item Package name of the item to remove from the favorites list */ void FMainMRUFavoritesList::RemoveFavoritesItem( const FString& Item ) { - const FString CleanedName = FPaths::ConvertRelativePathToFull(Item); - const int32 ItemIndex = FavoriteItems.Find( CleanedName ); + check(FPackageName::IsValidLongPackageName(Item)); + const int32 ItemIndex = FavoriteItems.Find( Item ); if ( ItemIndex != INDEX_NONE ) { FavoriteItems.RemoveAt( ItemIndex ); @@ -72,27 +73,28 @@ void FMainMRUFavoritesList::RemoveFavoritesItem( const FString& Item ) /** * Moves the specified favorites item to the head of the list * - * @param Item Filename of the item to move + * @param Item Package name of the item to move */ void FMainMRUFavoritesList::MoveFavoritesItemToHead(const FString& Item) { - const FString CleanedName = FPaths::ConvertRelativePathToFull(Item); + check(FPackageName::IsValidLongPackageName(Item)); if ( FavoriteItems.RemoveSingle(Item) == 1 ) { - FavoriteItems.Insert( CleanedName, 0 ); + FavoriteItems.Insert( Item, 0 ); WriteToINI(); } } /** - * Returns whether a filename is favorited or not + * Returns whether a package name is favorited or not * - * @param Item Filename of the item to check + * @param Item Package name of the item to check * * @return true if the provided item is in the favorite's list; false if it is not */ bool FMainMRUFavoritesList::ContainsFavoritesItem( const FString& Item ) { + check(FPackageName::IsValidLongPackageName(Item)); const FString CleanedName = FPaths::ConvertRelativePathToFull(Item); return FavoriteItems.Contains( CleanedName ); } @@ -121,19 +123,21 @@ FString FMainMRUFavoritesList::GetFavoritesItem( int32 ItemIndex ) const bool FMainMRUFavoritesList::VerifyFavoritesFile( int32 ItemIndex ) { check( FavoriteItems.IsValidIndex( ItemIndex ) ); - const FString& CurFileName = FavoriteItems[ ItemIndex ]; + const FString& CurPackageName = FavoriteItems[ ItemIndex ]; + + FString CurFileName; + bool bSuccess = FPackageName::TryConvertLongPackageNameToFilename(CurPackageName, CurFileName, FPackageName::GetMapPackageExtension()); - const bool bFileExists = IFileManager::Get().FileSize( *CurFileName ) != INDEX_NONE; - // If the file doesn't exist any more, remove it from the favorites list and alert the user - if ( !bFileExists ) + if ( !bSuccess || IFileManager::Get().FileSize(*CurFileName) == INDEX_NONE ) { - FNotificationInfo Info(FText::Format(NSLOCTEXT("UnrealEd", "Error_FavoritesFileDoesNotExist", "Map '{0}' does not exist - it will be removed from the Favorites list."), FText::FromString(FPaths::GetCleanFilename(CurFileName)))); + FNotificationInfo Info(FText::Format(NSLOCTEXT("UnrealEd", "Error_FavoritesFileDoesNotExist", "Map '{0}' does not exist - it will be removed from the Favorites list."), FText::FromString(CurPackageName))); Info.bUseThrobber = false; Info.ExpireDuration = 8.0f; FSlateNotificationManager::Get().AddNotification(Info)->SetCompletionState(SNotificationItem::CS_Fail); - RemoveFavoritesItem( CurFileName ); + RemoveFavoritesItem(CurPackageName); + return false; } - return bFileExists; + return true; } diff --git a/Engine/Source/Editor/UnrealEd/Private/MRUList.cpp b/Engine/Source/Editor/UnrealEd/Private/MRUList.cpp index 77ea305c3df5..3dd9f02985de 100644 --- a/Engine/Source/Editor/UnrealEd/Private/MRUList.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/MRUList.cpp @@ -56,11 +56,11 @@ void FMRUList::MoveToTop(int32 InItem) void FMRUList::AddMRUItem(const FString& InItem) { - FString CleanedName = FPaths::ConvertRelativePathToFull(InItem); + check(FPackageName::IsValidLongPackageName(InItem)); // See if the item already exists in the list. If so, // move it to the top of the list and leave. - const int32 ItemIndex = Items.Find( CleanedName ); + const int32 ItemIndex = Items.Find(InItem); if ( ItemIndex != INDEX_NONE ) { MoveToTop( ItemIndex ); @@ -68,9 +68,9 @@ void FMRUList::AddMRUItem(const FString& InItem) else { // Item is new, so add it to the bottom of the list. - if( CleanedName.Len() ) + if(InItem.Len() ) { - new(Items) FString( *CleanedName ); + new(Items) FString( *InItem ); MoveToTop( Items.Num()-1 ); } @@ -83,6 +83,8 @@ void FMRUList::AddMRUItem(const FString& InItem) int32 FMRUList::FindMRUItemIdx(const FString& InItem) const { + check(FPackageName::IsValidLongPackageName(InItem)); + for( int32 mru = 0 ; mru < Items.Num() ; ++mru ) { if( Items[mru] == InItem ) @@ -114,16 +116,37 @@ void FMRUList::InternalReadINI( TArray& OutItems, const FString& INISec // Clear existing items OutItems.Empty(); + bool bConvertedToNewFormat = false; + // Iterate over the maximum number of provided elements for( int32 ItemIdx = 0 ; ItemIdx < NumElements ; ++ItemIdx ) { // Try to find data for a key formed as "INIKeyBaseItemIdx" for the provided INI section. If found, add the data to the output item array. FString CurItem; - if ( GConfig->GetString( *INISection, *FString::Printf( TEXT("%s%d"), *INIKeyBase, ItemIdx ), CurItem, GEditorPerProjectIni ) ) + if (GConfig->GetString(*INISection, *FString::Printf(TEXT("%s%d"), *INIKeyBase, ItemIdx), CurItem, GEditorPerProjectIni)) { - OutItems.AddUnique( FPaths::ConvertRelativePathToFull(CurItem) ); + if (!FPackageName::IsValidLongPackageName(CurItem)) + { + FString NewItem; + if (FPackageName::TryConvertFilenameToLongPackageName(CurItem, NewItem)) + { + CurItem = NewItem; + OutItems.AddUnique(CurItem); + } + + bConvertedToNewFormat = true; + } + else + { + OutItems.AddUnique(CurItem); + } } } + + if (bConvertedToNewFormat) + { + InternalWriteINI(OutItems, INISection, INIKeyBase); + } } @@ -143,16 +166,19 @@ void FMRUList::InternalWriteINI( const TArray& InItems, const FString& bool FMRUList::VerifyMRUFile(int32 InItem) { check( InItem > -1 && InItem < GetMaxItems() ); - const FString filename = Items[InItem]; + const FString PackageName = Items[InItem]; + + FString Filename; + bool bSuccess = FPackageName::TryConvertLongPackageNameToFilename(PackageName, Filename, FPackageName::GetMapPackageExtension()); // If the file doesn't exist, tell the user about it, remove the file from the list - if( IFileManager::Get().FileSize( *filename ) == -1 ) + if( !bSuccess || IFileManager::Get().FileSize( *Filename) == INDEX_NONE ) { FMessageLog EditorErrors("EditorErrors"); FFormatNamedArguments Arguments; - Arguments.Add(TEXT("FileName"), FText::FromString(filename)); - EditorErrors.Warning(FText::Format( NSLOCTEXT("MRUList", "Error_FileDoesNotExist", "File does not exist : '{FileName}'. It will be removed from the recent items list."), Arguments ) ); - EditorErrors.Notify(NSLOCTEXT("MRUList", "Notification_FileDoesNotExist", "File does not exist! Removed from recent items list!")); + Arguments.Add(TEXT("PackageName"), FText::FromString(PackageName)); + EditorErrors.Warning(FText::Format( NSLOCTEXT("MRUList", "Error_FileDoesNotExist", "Map '{PackageName}' does not exist. It will be removed from the recent items list."), Arguments ) ); + EditorErrors.Notify(NSLOCTEXT("MRUList", "Notification_PackageDoesNotExist", "Map does not exist! Removed from recent items list!")); RemoveMRUItem( InItem ); WriteToINI(); diff --git a/Engine/Source/Editor/UnrealEd/Private/PlayLevel.cpp b/Engine/Source/Editor/UnrealEd/Private/PlayLevel.cpp index f9a0f8010bf4..fc2b5100ee45 100644 --- a/Engine/Source/Editor/UnrealEd/Private/PlayLevel.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/PlayLevel.cpp @@ -2474,6 +2474,9 @@ void UEditorEngine::SpawnIntraProcessPIEWorlds(bool bAnyBlueprintErrors, bool bS // Restore window settings GetMultipleInstancePositions(0, NextX, NextY); // restore cached settings + + // Give focus to the first client + GiveFocusToFirstClientPIEViewport(); } bool UEditorEngine::CreatePIEWorldFromLogin(FWorldContext& PieWorldContext, EPlayNetMode PlayNetMode, FPieLoginStruct& DataStruct) @@ -2565,6 +2568,9 @@ void UEditorEngine::LoginPIEInstances(bool bAnyBlueprintErrors, bool bStartInSpe const EPlayNetMode PlayNetMode = [&PlayInSettings]{ EPlayNetMode NetMode(PIE_Standalone); return (PlayInSettings->GetPlayNetMode(NetMode) ? NetMode : PIE_Standalone); }(); const bool CanPlayNetDedicated = [&PlayInSettings]{ bool PlayNetDedicated(false); return (PlayInSettings->GetPlayNetDedicated(PlayNetDedicated) && PlayNetDedicated); }(); const bool WillAutoConnectToServer = [&PlayInSettings]{ bool AutoConnectToServer(false); return (PlayInSettings->GetAutoConnectToServer(AutoConnectToServer) && AutoConnectToServer); }(); + const int32 PlayNumberOfClients = [&PlayInSettings] { int32 NumberOfClients(0); return (PlayInSettings->GetPlayNumberOfClients(NumberOfClients) ? NumberOfClients : 0); }(); + + PIEInstancesToLogInCount = PlayNumberOfClients; // Server if (WillAutoConnectToServer || CanPlayNetDedicated) @@ -2620,7 +2626,6 @@ void UEditorEngine::LoginPIEInstances(bool bAnyBlueprintErrors, bool bStartInSpe } // Clients - const int32 PlayNumberOfClients = [&PlayInSettings]{ int32 NumberOfClients(0); return (PlayInSettings->GetPlayNumberOfClients(NumberOfClients) ? NumberOfClients : 0); }(); for (; ClientNum < PlayNumberOfClients; ++ClientNum) { PlayInSettings->SetPlayNetMode(PlayNetMode); @@ -2711,6 +2716,41 @@ void UEditorEngine::OnLoginPIEComplete_Deferred(int32 LocalUserNum, bool bWasSuc } } } + + PIEInstancesToLogInCount--; + if (PIEInstancesToLogInCount == 0) + { + OnLoginPIEAllComplete(); + } +} + +void UEditorEngine::OnLoginPIEAllComplete() +{ + GiveFocusToFirstClientPIEViewport(); +} + +void UEditorEngine::GiveFocusToFirstClientPIEViewport() +{ + // Find the non-dedicated server or first client window to give focus to + int32 LowestPIEInstance = TNumericLimits::Max(); + UGameViewportClient* ViewportClient = nullptr; + for (const FWorldContext& WorldContext : WorldList) + { + if (WorldContext.WorldType == EWorldType::PIE && !WorldContext.RunAsDedicated) + { + if (WorldContext.PIEInstance < LowestPIEInstance) + { + LowestPIEInstance = WorldContext.PIEInstance; + ViewportClient = WorldContext.GameViewport; + } + } + } + + // Give focus to the first client + if (ViewportClient && ViewportClient->GetGameViewportWidget().IsValid()) + { + FSlateApplication::Get().RegisterGameViewport(ViewportClient->GetGameViewportWidget().ToSharedRef()); + } } void UEditorEngine::RequestLateJoin() diff --git a/Engine/Source/Editor/UnrealEd/Private/Settings/SettingsClasses.cpp b/Engine/Source/Editor/UnrealEd/Private/Settings/SettingsClasses.cpp index 5b4f037a2ed4..7a836d58e0ca 100644 --- a/Engine/Source/Editor/UnrealEd/Private/Settings/SettingsClasses.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/Settings/SettingsClasses.cpp @@ -126,12 +126,11 @@ void UEditorExperimentalSettings::PostEditChangeProperty( struct FPropertyChange UEditorLoadingSavingSettings::UEditorLoadingSavingSettings( const FObjectInitializer& ObjectInitializer ) : Super(ObjectInitializer) - , bEnableSourceControlCompatabilityCheck(true) , bMonitorContentDirectories(true) , AutoReimportThreshold(3.f) , bAutoCreateAssets(true) , bAutoDeleteAssets(true) - , bDetectChangesOnStartup(false) + , bDetectChangesOnStartup(true) , bDeleteSourceFilesWithAssets(false) { TextDiffToolPath.FilePath = TEXT("P4Merge.exe"); @@ -187,64 +186,6 @@ void UEditorLoadingSavingSettings::PostInitProperties() Super::PostInitProperties(); } -void UEditorLoadingSavingSettings::CheckSourceControlCompatability() -{ - if (!bEnableSourceControlCompatabilityCheck || !bMonitorContentDirectories) - { - return; - } - - if (ISourceControlModule::Get().IsEnabled() && bDetectChangesOnStartup) - { - // Persistent shared payload captured by the lambdas below - struct FPersistentPayload { TSharedPtr Notification; }; - TSharedRef Payload = MakeShareable(new FPersistentPayload); - - FNotificationInfo Info(LOCTEXT("AutoReimport_NotificationTitle", "We noticed that your auto-reimport settings are set up to detect source content changes on restart.\nThis might cause unexpected behavior when starting up after getting latest from source control.\n\nWe recommend disabling this specific behavior.")); - - auto OnTurnOffClicked = [=]{ - auto* Settings = GetMutableDefault(); - Settings->bDetectChangesOnStartup = false; - Settings->SaveConfig(); - - Payload->Notification->SetEnabled(false); - Payload->Notification->Fadeout(); - }; - Info.ButtonDetails.Emplace(LOCTEXT("AutoReimport_TurnOff", "Don't detect changes on start-up"), FText(), FSimpleDelegate::CreateLambda(OnTurnOffClicked), SNotificationItem::ECompletionState::CS_None); - - auto OnIgnoreClicked = [=]{ - - Payload->Notification->SetEnabled(false); - Payload->Notification->Fadeout(); - }; - Info.ButtonDetails.Emplace(LOCTEXT("AutoReimport_Ignore", "Ignore"), FText(), FSimpleDelegate::CreateLambda(OnIgnoreClicked), SNotificationItem::ECompletionState::CS_None); - - Info.bUseLargeFont = false; - Info.bFireAndForget = false; - - Info.CheckBoxStateChanged = FOnCheckStateChanged::CreateLambda([](ECheckBoxState State){ - auto* Settings = GetMutableDefault(); - Settings->bEnableSourceControlCompatabilityCheck = (State != ECheckBoxState::Checked); - Settings->SaveConfig(); - }); - Info.CheckBoxText = LOCTEXT("AutoReimport_DontShowAgain", "Don't show again"); - - Info.Hyperlink = FSimpleDelegate::CreateLambda([]{ - // Open Settings - ISettingsModule* SettingsModule = FModuleManager::GetModulePtr("Settings"); - if (SettingsModule != nullptr) - { - // Ensure that the advanced properties are visible - GConfig->SetBool(TEXT("DetailCategoriesAdvanced"), TEXT("EditorLoadingSavingSettings.AutoReimport"), true, GEditorPerProjectIni); - SettingsModule->ShowViewer("Editor", "General", "LoadingSaving"); - } - }); - Info.HyperlinkText = LOCTEXT("AutoReimport_OpenSettings", "Settings"); - - Payload->Notification = FSlateNotificationManager::Get().AddNotification(Info); - } -} - FAutoReimportDirectoryConfig::FParseContext::FParseContext(bool bInEnableLogging) : bEnableLogging(bInEnableLogging) { diff --git a/Engine/Source/Editor/UnrealEd/Private/Toolkits/AssetEditorManager.cpp b/Engine/Source/Editor/UnrealEd/Private/Toolkits/AssetEditorManager.cpp index b68561742db9..78a376d1f734 100644 --- a/Engine/Source/Editor/UnrealEd/Private/Toolkits/AssetEditorManager.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/Toolkits/AssetEditorManager.cpp @@ -706,4 +706,12 @@ void FAssetEditorManager::OpenEditorsForAssets(const TArray& AssetsToOp } } +void FAssetEditorManager::OpenEditorsForAssets(const TArray& AssetsToOpen) +{ + for (const FName AssetName : AssetsToOpen) + { + OpenEditorForAsset(AssetName.ToString()); + } +} + #undef LOCTEXT_NAMESPACE \ No newline at end of file diff --git a/Engine/Source/Editor/UnrealEd/Private/UnrealEdEngine.cpp b/Engine/Source/Editor/UnrealEd/Private/UnrealEdEngine.cpp index aa6087af18b1..130e6df12f11 100644 --- a/Engine/Source/Editor/UnrealEd/Private/UnrealEdEngine.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/UnrealEdEngine.cpp @@ -115,8 +115,6 @@ void UUnrealEdEngine::Init(IEngineLoop* InEngineLoop) { AutoReimportManager = NewObject(); AutoReimportManager->Initialize(); - - GetMutableDefault()->CheckSourceControlCompatability(); } // register details panel customizations diff --git a/Engine/Source/Editor/UnrealEd/Public/Factories.h b/Engine/Source/Editor/UnrealEd/Public/Factories.h index bc31fdafbd78..0cdf9a01a26b 100644 --- a/Engine/Source/Editor/UnrealEd/Public/Factories.h +++ b/Engine/Source/Editor/UnrealEd/Public/Factories.h @@ -39,7 +39,7 @@ public: protected: /** Return true if the an object of type ObjectClass is allowed to be created; If false is returned, the object and subobjects will be ignored. */ - virtual bool CanCreateClass(UClass* ObjectClass) const; + virtual bool CanCreateClass(UClass* ObjectClass, bool& bOmitSubObjs) const; /** This is called on each created object after the property text is imported */ virtual void ProcessConstructedObject(UObject* CreatedObject); diff --git a/Engine/Source/Editor/UnrealEd/Public/MRUList.h b/Engine/Source/Editor/UnrealEd/Public/MRUList.h index bf3c02f00137..3bf83172744d 100644 --- a/Engine/Source/Editor/UnrealEd/Public/MRUList.h +++ b/Engine/Source/Editor/UnrealEd/Public/MRUList.h @@ -33,7 +33,7 @@ public: /** * Adds an item to the MRU list, moving it to the top. * - * @param Item The item to add. + * @param Item The long package name of the item to add. */ void AddMRUItem(const FString& Item); diff --git a/Engine/Source/Editor/UnrealEd/Public/Toolkits/AssetEditorManager.h b/Engine/Source/Editor/UnrealEd/Public/Toolkits/AssetEditorManager.h index 0ae6d0a4b819..03382362dda6 100644 --- a/Engine/Source/Editor/UnrealEd/Public/Toolkits/AssetEditorManager.h +++ b/Engine/Source/Editor/UnrealEd/Public/Toolkits/AssetEditorManager.h @@ -66,6 +66,7 @@ public: /** Opens editors for the supplied assets (via OpenEditorForAsset) */ void OpenEditorsForAssets(const TArray& AssetsToOpen); + void OpenEditorsForAssets(const TArray& AssetsToOpen); /** Returns the primary editor if one is already open for the specified asset. * If there is one open and bFocusIfOpen is true, that editor will be brought to the foreground and focused if possible. diff --git a/Engine/Source/Editor/UnrealEd/UnrealEd.Build.cs b/Engine/Source/Editor/UnrealEd/UnrealEd.Build.cs index 554d74447d90..a2d9800e7e5a 100644 --- a/Engine/Source/Editor/UnrealEd/UnrealEd.Build.cs +++ b/Engine/Source/Editor/UnrealEd/UnrealEd.Build.cs @@ -45,7 +45,8 @@ public class UnrealEd : ModuleRules "PlacementMode", "Settings", "SettingsEditor", - "SoundClassEditor", + "SuperSearch", + "SoundClassEditor", "ViewportSnapping", "SourceCodeAccess", "ReferenceViewer", @@ -122,7 +123,6 @@ public class UnrealEd : ModuleRules "SoundClassEditor", "SoundCueEditor", "SourceControlWindows", - "SuperSearch", "StatsViewer", "SwarmInterface", "TargetPlatform", @@ -182,7 +182,8 @@ public class UnrealEd : ModuleRules "SettingsEditor", "SessionFrontend", "Sequencer", - "GeometryMode", + "SuperSearch", + "GeometryMode", "TextureAlignMode", "FoliageEdit", "PackageDependencyInfo", @@ -230,7 +231,6 @@ public class UnrealEd : ModuleRules { "GraphEditor", "Kismet", - "SuperSearch", } ); diff --git a/Engine/Source/Programs/AutomationTool/AutomationUtils/ProjectUtils.cs b/Engine/Source/Programs/AutomationTool/AutomationUtils/ProjectUtils.cs index bb62e8ce5108..520f72fd7dd5 100644 --- a/Engine/Source/Programs/AutomationTool/AutomationUtils/ProjectUtils.cs +++ b/Engine/Source/Programs/AutomationTool/AutomationUtils/ProjectUtils.cs @@ -283,26 +283,25 @@ namespace AutomationTool List ExtraSearchPaths = null; if (RawProjectPath != null) { + string TempTargetDir = CommandUtils.CombinePaths(Path.GetDirectoryName(RawProjectPath.FullName), "Intermediate", "Source"); if (RequiresTempTarget(RawProjectPath, ClientTargetPlatforms, AssetNativizationRequested)) { GenerateTempTarget(RawProjectPath); Properties.bWasGenerated = true; ExtraSearchPaths = new List(); - - string TempTargetDir = CommandUtils.CombinePaths(Path.GetDirectoryName(RawProjectPath.FullName), "Intermediate", "Source"); ExtraSearchPaths.Add(TempTargetDir); - - // in case the RulesCompiler (what we use to find all the - // Target.cs files) has already cached the contents of this - // directory, then we need to invalidate that cache (so - // it'll find/use the new Target.cs file) - RulesCompiler.InvalidateRulesFileCache(TempTargetDir); } else if (File.Exists(Path.Combine(Path.GetDirectoryName(RawProjectPath.FullName), "Intermediate", "Source", Path.GetFileNameWithoutExtension(RawProjectPath.FullName) + ".Target.cs"))) { File.Delete(Path.Combine(Path.GetDirectoryName(RawProjectPath.FullName), "Intermediate", "Source", Path.GetFileNameWithoutExtension(RawProjectPath.FullName) + ".Target.cs")); } - } + + // in case the RulesCompiler (what we use to find all the + // Target.cs files) has already cached the contents of this + // directory, then we need to invalidate that cache (so + // it'll find/use the new Target.cs file) + RulesCompiler.InvalidateRulesFileCache(TempTargetDir); + } if (CommandUtils.CmdEnv.HasCapabilityToCompile) { diff --git a/Engine/Source/Programs/AutomationTool/GUBP/ElectricCommander.cs b/Engine/Source/Programs/AutomationTool/GUBP/ElectricCommander.cs index 5b840f2a800d..23a65a49f801 100644 --- a/Engine/Source/Programs/AutomationTool/GUBP/ElectricCommander.cs +++ b/Engine/Source/Programs/AutomationTool/GUBP/ElectricCommander.cs @@ -464,7 +464,7 @@ namespace AutomationTool JsonWriter.WriteValue("DescriptionText", NodeToDo.DescriptionText); if (NodeToDo.RecipientsForFailureEmails.Length > 0) { - JsonWriter.WriteValue("Notify", String.Join(" ", NodeToDo.RecipientsForFailureEmails)); + JsonWriter.WriteValue("Notify", String.Join(";", NodeToDo.RecipientsForFailureEmails)); } JsonWriter.WriteValue("IsTrigger", true); JsonWriter.WriteObjectEnd(); diff --git a/Engine/Source/Programs/ShaderCompileWorker/Private/ShaderCompileWorker.cpp b/Engine/Source/Programs/ShaderCompileWorker/Private/ShaderCompileWorker.cpp index 430aff5df0ad..45387d613c10 100644 --- a/Engine/Source/Programs/ShaderCompileWorker/Private/ShaderCompileWorker.cpp +++ b/Engine/Source/Programs/ShaderCompileWorker/Private/ShaderCompileWorker.cpp @@ -580,8 +580,8 @@ static EShaderPlatform FormatNameToEnum(FName ShaderFormat) if (ShaderFormat == NAME_VULKAN_SM4) return SP_VULKAN_SM4; if (ShaderFormat == NAME_VULKAN_SM5) return SP_VULKAN_SM5; if (ShaderFormat == NAME_VULKAN_ES3_1_ANDROID) return SP_VULKAN_ES3_1_ANDROID; - if (ShaderFormat == NAME_VULKAN_ES3_1) return SP_VULKAN_ES3_1_ANDROID; - if (ShaderFormat == NAME_VULKAN_ES3_1_UB) return SP_VULKAN_ES3_1_ANDROID; + if (ShaderFormat == NAME_VULKAN_ES3_1) return SP_VULKAN_PCES3_1; + if (ShaderFormat == NAME_VULKAN_ES3_1_UB) return SP_VULKAN_PCES3_1; if (ShaderFormat == NAME_SF_METAL_SM4) return SP_METAL_SM4; if (ShaderFormat == NAME_SF_METAL_MACES3_1) return SP_METAL_MACES3_1; return SP_NumPlatforms; diff --git a/Engine/Source/Programs/UnrealBuildTool/Configuration/UEBuildTarget.cs b/Engine/Source/Programs/UnrealBuildTool/Configuration/UEBuildTarget.cs index 13540ad10f42..f585bf9a8ef5 100644 --- a/Engine/Source/Programs/UnrealBuildTool/Configuration/UEBuildTarget.cs +++ b/Engine/Source/Programs/UnrealBuildTool/Configuration/UEBuildTarget.cs @@ -3561,6 +3561,10 @@ namespace UnrealBuildTool } } + // Remove any enabled plugins that are unused on the current platform. This prevents having to stage the .uplugin files, but requires that the project descriptor + // doesn't have a platform-neutral reference to it. + EnabledPlugins.RemoveAll(Plugin => !UProjectInfo.IsPluginDescriptorRequiredForProject(Plugin, ProjectDescriptor, Platform, TargetType, UEBuildConfiguration.bBuildDeveloperTools, UEBuildConfiguration.bBuildEditor)); + // Set the list of plugins that should be built if (Rules.bBuildAllPlugins) { diff --git a/Engine/Source/Programs/UnrealBuildTool/System/UProjectInfo.cs b/Engine/Source/Programs/UnrealBuildTool/System/UProjectInfo.cs index 13bee2fe937b..729c20e32b52 100644 --- a/Engine/Source/Programs/UnrealBuildTool/System/UProjectInfo.cs +++ b/Engine/Source/Programs/UnrealBuildTool/System/UProjectInfo.cs @@ -320,5 +320,45 @@ namespace UnrealBuildTool } return bEnabled; } + + /// + /// Determine if a plugin is enabled for a given project + /// + /// The project to check + /// Information about the plugin + /// The target platform + /// True if the plugin should be enabled for this project + public static bool IsPluginDescriptorRequiredForProject(PluginInfo Plugin, ProjectDescriptor Project, UnrealTargetPlatform Platform, TargetRules.TargetType TargetType, bool bBuildDeveloperTools, bool bBuildEditor) + { + // Check if it's referenced by name from the project descriptor. If it is, we'll need the plugin to be included with the project regardless of whether it has + // any platform-specific modules or content, just so the runtime can make the call. + if (Project != null && Project.Plugins != null) + { + foreach (PluginReferenceDescriptor PluginReference in Project.Plugins) + { + if (String.Compare(PluginReference.Name, Plugin.Name, true) == 0) + { + return PluginReference.IsEnabledForPlatform(Platform) && PluginReference.IsEnabledForTarget(TargetType); + } + } + } + + // If the plugin contains content, it should be included for all platforms + if(Plugin.Descriptor.bCanContainContent) + { + return true; + } + + // Check if the plugin has any modules for the given target + foreach (ModuleDescriptor Module in Plugin.Descriptor.Modules) + { + if(Module.IsCompiledInConfiguration(Platform, TargetType, bBuildDeveloperTools, bBuildEditor)) + { + return true; + } + } + + return false; + } } } diff --git a/Engine/Source/Programs/UnrealBuildTool/System/VCProjectFileGenerator.cs b/Engine/Source/Programs/UnrealBuildTool/System/VCProjectFileGenerator.cs index 58063a345c1d..ba67fc6130d7 100644 --- a/Engine/Source/Programs/UnrealBuildTool/System/VCProjectFileGenerator.cs +++ b/Engine/Source/Programs/UnrealBuildTool/System/VCProjectFileGenerator.cs @@ -282,13 +282,6 @@ namespace UnrealBuildTool { VCProjectFileFormat ProposedFormat = ProjectFileFormat; - // Visual Studio 2015 is not supported by PS4 VSI - if( SupportedPlatform == UnrealTargetPlatform.PS4 ) - { - Log.TraceInformation("Forcing Visual Studio max version to 2013 projects for PS4 compatibility (use '-2015' to override.)"); - ProposedFormat = VCProjectFileFormat.VisualStudio2013; - } - // Visual Studio 2015 is not supported by the Android debugger we currently furnish if (SupportedPlatform == UnrealTargetPlatform.Android) { diff --git a/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_TwistCorrectiveNode.h b/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_TwistCorrectiveNode.h index 01042797be20..ddbd895a9848 100644 --- a/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_TwistCorrectiveNode.h +++ b/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_TwistCorrectiveNode.h @@ -59,7 +59,10 @@ struct FReferenceBoneFrame }; /** - * This is the runtime version of a bone driven controller, which maps part of the state from one bone to another (e.g., 2 * source.x -> target.z) + * This is the node that apply corrective morphtarget for twist + * Good example is that if you twist your neck too far right or left, you're going to see odd stretch shape of neck, + * This node can detect the angle and apply morphtarget curve + * This isn't the twist control node for bone twist */ USTRUCT() struct ANIMGRAPHRUNTIME_API FAnimNode_TwistCorrectiveNode : public FAnimNode_SkeletalControlBase diff --git a/Engine/Source/Runtime/AppFramework/Private/Widgets/Colors/SColorPicker.cpp b/Engine/Source/Runtime/AppFramework/Private/Widgets/Colors/SColorPicker.cpp index eedb0ef80673..5ade0d2dac6f 100644 --- a/Engine/Source/Runtime/AppFramework/Private/Widgets/Colors/SColorPicker.cpp +++ b/Engine/Source/Runtime/AppFramework/Private/Widgets/Colors/SColorPicker.cpp @@ -1291,10 +1291,16 @@ void SColorPicker::HandleColorSpinBoxValueChanged( float NewValue, EColorPickerC } -void SColorPicker::HandleEyeDropperButtonComplete() +void SColorPicker::HandleEyeDropperButtonComplete(bool bCancelled) { bIsInteractive = false; + if (bCancelled) + { + SetNewTargetColorHSV(OldColor, true); + RestoreColors(); + } + if (bOnlyRefreshOnMouseUp || bPerfIsTooSlowToUpdate) { UpdateColorPick(); diff --git a/Engine/Source/Runtime/AppFramework/Private/Widgets/Colors/SEyeDropperButton.cpp b/Engine/Source/Runtime/AppFramework/Private/Widgets/Colors/SEyeDropperButton.cpp index be1679644b7b..0f753762138b 100644 --- a/Engine/Source/Runtime/AppFramework/Private/Widgets/Colors/SEyeDropperButton.cpp +++ b/Engine/Source/Runtime/AppFramework/Private/Widgets/Colors/SEyeDropperButton.cpp @@ -105,7 +105,8 @@ FReply SEyeDropperButton::OnMouseButtonUp(const FGeometry& MyGeometry, const FPo Reply.ReleaseMouseCapture(); - OnComplete.ExecuteIfBound(); + const bool bCancelled = false; + OnComplete.ExecuteIfBound(bCancelled); } else if ( MouseEvent.GetEffectingButton() == EKeys::LeftMouseButton && bWasClicked ) { @@ -167,7 +168,8 @@ FReply SEyeDropperButton::OnKeyDown(const FGeometry& MyGeometry, const FKeyEvent FReply ReleaseReply = FReply::Handled().ReleaseMouseCapture(); - OnComplete.ExecuteIfBound(); + const bool bCancelled = true; + OnComplete.ExecuteIfBound(bCancelled); return ReleaseReply; } diff --git a/Engine/Source/Runtime/AppFramework/Private/Widgets/Colors/SEyeDropperButton.h b/Engine/Source/Runtime/AppFramework/Private/Widgets/Colors/SEyeDropperButton.h index 1168467faf22..599532c7672d 100644 --- a/Engine/Source/Runtime/AppFramework/Private/Widgets/Colors/SEyeDropperButton.h +++ b/Engine/Source/Runtime/AppFramework/Private/Widgets/Colors/SEyeDropperButton.h @@ -12,7 +12,7 @@ class SEyeDropperButton : public SButton { public: - DECLARE_DELEGATE(FOnDropperComplete) + DECLARE_DELEGATE_OneParam(FOnDropperComplete, bool) SLATE_BEGIN_ARGS( SEyeDropperButton ) : _OnValueChanged() @@ -22,7 +22,7 @@ public: {} /** Invoked when a new value is selected by the dropper */ - SLATE_EVENT(FOnLinearColorValueChanged, OnValueChanged) + SLATE_EVENT(FOnLinearColorValueChanged, OnValueChanged) /** Invoked when the dropper goes from inactive to active */ SLATE_EVENT(FSimpleDelegate, OnBegin) diff --git a/Engine/Source/Runtime/AppFramework/Public/Widgets/Colors/SColorPicker.h b/Engine/Source/Runtime/AppFramework/Public/Widgets/Colors/SColorPicker.h index 6f47fe3107b7..b90256e2db55 100644 --- a/Engine/Source/Runtime/AppFramework/Public/Widgets/Colors/SColorPicker.h +++ b/Engine/Source/Runtime/AppFramework/Public/Widgets/Colors/SColorPicker.h @@ -269,7 +269,7 @@ private: void HandleColorSpinBoxValueChanged( float NewValue, EColorPickerChannels Channel ); // Callback for completed eye dropper interactions. - void HandleEyeDropperButtonComplete(); + void HandleEyeDropperButtonComplete(bool bCancelled); // Callback for getting the text in the hex linear box. FText HandleHexLinearBoxText() const; diff --git a/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalCommandEncoder.cpp b/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalCommandEncoder.cpp index 441a9788cc4d..4107dde94dae 100644 --- a/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalCommandEncoder.cpp +++ b/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalCommandEncoder.cpp @@ -74,6 +74,7 @@ FMetalCommandEncoder::~FMetalCommandEncoder(void) [DepthStencilState release]; } [RenderPassDesc release]; + RenderPassDesc = nil; if(DebugGroups) { @@ -206,6 +207,11 @@ bool FMetalCommandEncoder::IsBlitCommandEncoderActive(void) const return BlitCommandEncoder != nil; } +bool FMetalCommandEncoder::IsRenderPassDescriptorValid(void) const +{ + return (RenderPassDesc != nil); +} + id FMetalCommandEncoder::GetRenderCommandEncoder(void) const { return RenderCommandEncoder; @@ -514,6 +520,7 @@ void FMetalCommandEncoder::SetRenderPassDescriptor(MTLRenderPassDescriptor* cons } RenderPassDesc = RenderPass; } + check(RenderPassDesc); if (bReset) { diff --git a/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalCommandEncoder.h b/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalCommandEncoder.h index dab600076336..f2820beb9bde 100644 --- a/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalCommandEncoder.h +++ b/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalCommandEncoder.h @@ -52,6 +52,9 @@ public: /** @returns True if and only if there is an active blit command encoder, otherwise false. */ bool IsBlitCommandEncoderActive(void) const; + + /** @returns True if and only if there is valid render pass descriptor set on the encoder, otherwise false. */ + bool IsRenderPassDescriptorValid(void) const; /** @returns The active render command encoder or nil if there isn't one. */ id GetRenderCommandEncoder(void) const; diff --git a/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalCommands.cpp b/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalCommands.cpp index 7b26f7d846d0..9371a2de8ecf 100644 --- a/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalCommands.cpp +++ b/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalCommands.cpp @@ -886,13 +886,13 @@ void FMetalRHICommandContext::RHIClearMRT(bool bClearColor,int32 NumClearColors, if (Context->GetCurrentState().GetNumRenderTargets() <= 1) { - BlendStateRHI = (bClearColor && Context->GetCurrentState().GetHasValidRenderTarget()) + BlendStateRHI = (bClearColor && Context->GetCurrentState().GetHasValidColorTarget()) ? TStaticBlendState<>::GetRHI() : TStaticBlendState::GetRHI(); } else { - BlendStateRHI = (bClearColor && Context->GetCurrentState().GetHasValidRenderTarget()) + BlendStateRHI = (bClearColor && Context->GetCurrentState().GetHasValidColorTarget()) ? TStaticBlendState<>::GetRHI() : TStaticBlendStateWriteMask::GetRHI(); } diff --git a/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalContext.cpp b/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalContext.cpp index 1aa3fa6f7677..682c5730c993 100644 --- a/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalContext.cpp +++ b/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalContext.cpp @@ -387,10 +387,23 @@ void FMetalDeviceContext::EndDrawingViewport(FMetalViewport* Viewport, bool bPre // enqueue a present if desired if (bPresent) { - id Drawable = Viewport->GetDrawable(); - [CurrentCommandBuffer addScheduledHandler:^(id) { - [Drawable present]; - }]; + id Drawable = (id)Viewport->GetDrawable(); + if (Drawable.texture) + { +#if PLATFORM_MAC + id Blitter = GetBlitContext(); + + id Src = Viewport->GetBackBuffer()->Surface.Texture; + id Dst = Drawable.texture; + + [Blitter copyFromTexture:Src sourceSlice:0 sourceLevel:0 sourceOrigin:MTLOriginMake(0, 0, 0) sourceSize:MTLSizeMake(Src.width, Src.height, 1) toTexture:Dst destinationSlice:0 destinationLevel:0 destinationOrigin:MTLOriginMake(0, 0, 0)]; + + CommandEncoder.EndEncoding(); +#endif + [CurrentCommandBuffer addScheduledHandler:^(id) { + [Drawable present]; + }]; + } } // We may be limiting our framerate to the display link @@ -737,6 +750,9 @@ void FMetalContext::PrepareToDraw(uint32 PrimitiveType) TRefCountPtr CurrentBoundShaderState = StateCache.GetBoundShaderState(); + // Enforce calls to SetRenderTarget prior to issuing draw calls. + check(StateCache.GetHasValidRenderTarget()); + // Validate the vertex layout in debug mode, or when the validation layer is enabled for development builds. // Other builds will just crash & burn if it is incorrect. #if UE_BUILD_DEBUG || UE_BUILD_DEVELOPMENT @@ -795,6 +811,10 @@ void FMetalContext::PrepareToDraw(uint32 PrimitiveType) StateCache.SetRenderTargetsInfo(Info, StateCache.GetVisibilityResultsBuffer(), false); bRestoreState = true; + + // Enforce calls to SetRenderTarget prior to issuing draw calls. + check(StateCache.GetHasValidRenderTarget()); + check(CommandEncoder.IsRenderPassDescriptorValid()); } // make sure the BSS has a valid pipeline state object @@ -812,6 +832,14 @@ void FMetalContext::PrepareToDraw(uint32 PrimitiveType) if(!CommandEncoder.IsRenderCommandEncoderActive()) { + if (!CommandEncoder.IsRenderPassDescriptorValid()) + { + UE_LOG(LogMetal, Warning, TEXT("Re-binding the render-target because no RenderPassDescriptor was bound!")); + FRHISetRenderTargetsInfo Info = StateCache.GetRenderTargetsInfo(); + StateCache.SetHasValidRenderTarget(false); + StateCache.SetRenderTargetsInfo(Info, StateCache.GetVisibilityResultsBuffer(), false); + } + CommandEncoder.RestoreRenderCommandEncoding(); } else if (bRestoreState) diff --git a/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalRHI.cpp b/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalRHI.cpp index 0017c0850097..034d602f3aa1 100644 --- a/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalRHI.cpp +++ b/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalRHI.cpp @@ -103,7 +103,7 @@ FMetalDynamicRHI::FMetalDynamicRHI() GMaxRHIShaderPlatform = SP_METAL_SM4; } - GShaderPlatformForFeatureLevel[ERHIFeatureLevel::ES2] = SP_METAL_MACES3_1; + GShaderPlatformForFeatureLevel[ERHIFeatureLevel::ES2] = SP_METAL_MACES2; GShaderPlatformForFeatureLevel[ERHIFeatureLevel::ES3_1] = SP_METAL_MACES3_1; GShaderPlatformForFeatureLevel[ERHIFeatureLevel::SM4] = SP_METAL_SM4; GShaderPlatformForFeatureLevel[ERHIFeatureLevel::SM5] = (GMaxRHIFeatureLevel >= ERHIFeatureLevel::SM5) ? GMaxRHIShaderPlatform : SP_NumPlatforms; diff --git a/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalStateCache.cpp b/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalStateCache.cpp index 02458ac4ca26..8176f9ef6536 100644 --- a/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalStateCache.cpp +++ b/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalStateCache.cpp @@ -36,6 +36,7 @@ FMetalStateCache::FMetalStateCache(FMetalCommandEncoder& InCommandEncoder) , FrameBufferSize(CGSizeMake(0.0, 0.0)) , RenderTargetArraySize(1) , bHasValidRenderTarget(false) +, bHasValidColorTarget(false) , bScissorRectEnabled(false) { Viewport.originX = Viewport.originY = Viewport.width = Viewport.height = Viewport.znear = Viewport.zfar = 0.0; @@ -79,6 +80,7 @@ void FMetalStateCache::Reset(void) FMemory::Memzero(RenderTargetsInfo); bHasValidRenderTarget = false; + bHasValidColorTarget = false; FMemory::Memzero(DirtyUniformBuffers); @@ -264,6 +266,7 @@ void FMetalStateCache::SetRenderTargetsInfo(FRHISetRenderTargetsInfo const& InRe PipelineDesc.SampleCount = 0; bHasValidRenderTarget = false; + bHasValidColorTarget = false; uint8 ArrayTargets = 0; uint8 BoundTargets = 0; @@ -302,11 +305,8 @@ void FMetalStateCache::SetRenderTargetsInfo(FRHISetRenderTargetsInfo const& InRe BoundTargets |= 1 << RenderTargetIndex; - if (Surface.Texture == nil) - { - PipelineDesc.SampleCount = OldCount; - return; - } + // The surface cannot be nil - we have to have a valid render-target array after this call. + check (Surface.Texture != nil); // user code generally passes -1 as a default, but we need 0 uint32 ArraySliceIndex = RenderTargetView.ArraySliceIndex == 0xFFFFFFFF ? 0 : RenderTargetView.ArraySliceIndex; @@ -386,6 +386,7 @@ void FMetalStateCache::SetRenderTargetsInfo(FRHISetRenderTargetsInfo const& InRe [ColorAttachment release]; bHasValidRenderTarget = true; + bHasValidColorTarget = true; } else { @@ -552,6 +553,8 @@ void FMetalStateCache::SetRenderTargetsInfo(FRHISetRenderTargetsInfo const& InRe { PipelineDesc.SampleCount = DepthAttachment.texture.sampleCount; } + + bHasValidRenderTarget = true; // and assign it RenderPass.depthAttachment = DepthAttachment; @@ -592,6 +595,8 @@ void FMetalStateCache::SetRenderTargetsInfo(FRHISetRenderTargetsInfo const& InRe { PipelineDesc.SampleCount = StencilAttachment.texture.sampleCount; } + + bHasValidRenderTarget = true; // and assign it RenderPass.stencilAttachment = StencilAttachment; @@ -600,6 +605,7 @@ void FMetalStateCache::SetRenderTargetsInfo(FRHISetRenderTargetsInfo const& InRe [StencilAttachment release]; } } + check(bHasValidRenderTarget); // update hash for the depth/stencil buffer & sample count PipelineDesc.SetHashValue(Offset_DepthFormat, NumBits_DepthFormat, DepthFormatKey); @@ -629,11 +635,15 @@ void FMetalStateCache::SetRenderTargetsInfo(FRHISetRenderTargetsInfo const& InRe BoundShaderState.SafeRelease(); } } + + // Ensure that the RenderPassDesc is valid in the CommandEncoder. + check(CommandEncoder.IsRenderPassDescriptorValid()); } void FMetalStateCache::SetHasValidRenderTarget(bool InHasValidRenderTarget) { bHasValidRenderTarget = InHasValidRenderTarget; + bHasValidColorTarget = InHasValidRenderTarget; } void FMetalStateCache::SetViewport(const MTLViewport& InViewport) @@ -748,6 +758,7 @@ void FMetalStateCache::ConditionalUpdateBackBuffer(FMetalSurface& Surface) // set the texture into the backbuffer Surface.GetDrawableTexture(); } + check (Surface.Texture); } } @@ -756,7 +767,7 @@ bool FMetalStateCache::NeedsToSetRenderTarget(const FRHISetRenderTargetsInfo& In // see if our new Info matches our previous Info // basic checks - bool bAllChecksPassed = GetHasValidRenderTarget() && CommandEncoder.IsRenderCommandEncoderActive() && InRenderTargetsInfo.NumColorRenderTargets == RenderTargetsInfo.NumColorRenderTargets && + bool bAllChecksPassed = GetHasValidRenderTarget() && CommandEncoder.IsRenderPassDescriptorValid() && CommandEncoder.IsRenderCommandEncoderActive() && InRenderTargetsInfo.NumColorRenderTargets == RenderTargetsInfo.NumColorRenderTargets && // handle the case where going from backbuffer + depth -> backbuffer + null, no need to reset RT and do a store/load (InRenderTargetsInfo.DepthStencilRenderTarget.Texture == RenderTargetsInfo.DepthStencilRenderTarget.Texture || InRenderTargetsInfo.DepthStencilRenderTarget.Texture == nullptr); diff --git a/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalStateCache.h b/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalStateCache.h index 040b73d2da03..0a0adaab1ca4 100644 --- a/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalStateCache.h +++ b/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalStateCache.h @@ -54,8 +54,9 @@ public: FMetalComputeShader* GetComputeShader() const { return ComputeShader; } CGSize GetFrameBufferSize() const { return FrameBufferSize; } FRHISetRenderTargetsInfo const& GetRenderTargetsInfo() const { return RenderTargetsInfo; } - int32 GetNumRenderTargets() { return bHasValidRenderTarget ? RenderTargetsInfo.NumColorRenderTargets : -1; } + int32 GetNumRenderTargets() { return bHasValidColorTarget ? RenderTargetsInfo.NumColorRenderTargets : -1; } bool GetHasValidRenderTarget() const { return bHasValidRenderTarget; } + bool GetHasValidColorTarget() const { return bHasValidColorTarget; } const MTLViewport& GetViewport() const { return Viewport; } id GetVertexBuffer(uint32 const Index) { check(Index < MaxMetalStreams); return VertexBuffers[Index]; } uint32 GetVertexStride(uint32 const Index) { check(Index < MaxMetalStreams); return VertexStrides[Index]; } @@ -102,6 +103,6 @@ private: FRHISetRenderTargetsInfo RenderTargetsInfo; bool bHasValidRenderTarget; - + bool bHasValidColorTarget; bool bScissorRectEnabled; }; diff --git a/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalTexture.cpp b/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalTexture.cpp index 56d73be01b2d..1ca387d0716e 100644 --- a/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalTexture.cpp +++ b/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalTexture.cpp @@ -854,7 +854,7 @@ void* FMetalSurface::Lock(uint32 MipIndex, uint32 ArrayIndex, EResourceLockMode //kick the current command buffer. GetMetalDeviceContext().SubmitCommandBufferAndWait(); #endif - [Texture getBytes:LockedMemory[MipIndex] bytesPerRow:DestStride bytesPerImage:MipBytes fromRegion:Region mipmapLevel:MipIndex slice:ArrayIndex]; + [Texture getBytes:[LockedMemory[MipIndex] contents] bytesPerRow:DestStride bytesPerImage:MipBytes fromRegion:Region mipmapLevel:MipIndex slice:ArrayIndex]; } #if PLATFORM_MAC diff --git a/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalViewport.cpp b/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalViewport.cpp index 612beac34e12..68df4ae6d71f 100644 --- a/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalViewport.cpp +++ b/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalViewport.cpp @@ -80,20 +80,20 @@ FMetalViewport::FMetalViewport(void* WindowHandle, uint32 InSizeX,uint32 InSizeY FMetalViewport::~FMetalViewport() { - BackBuffer.SafeRelease(); + BackBuffer.SafeRelease(); // when the rest of the engine releases it, its framebuffers will be released too (those the engine knows about) check(!IsValidRef(BackBuffer)); } void FMetalViewport::Resize(uint32 InSizeX, uint32 InSizeY, bool bInIsFullscreen) { - BackBuffer.SafeRelease(); // when the rest of the engine releases it, its framebuffers will be released too (those the engine knows about) - FRHIResourceCreateInfo CreateInfo; - BackBuffer = (FMetalTexture2D*)(FTexture2DRHIParamRef)GDynamicRHI->RHICreateTexture2D(InSizeX, InSizeY, PF_B8G8R8A8, 1, 1, TexCreate_RenderTargetable | TexCreate_Presentable, CreateInfo); - BackBuffer->Surface.Viewport = this; + BackBuffer.SafeRelease(); // when the rest of the engine releases it, its framebuffers will be released too (those the engine knows about) + #if PLATFORM_MAC // @todo zebra: ios + BackBuffer = (FMetalTexture2D*)(FTexture2DRHIParamRef)GDynamicRHI->RHICreateTexture2D(InSizeX, InSizeY, PF_B8G8R8A8, 1, 1, TexCreate_RenderTargetable, CreateInfo); ((CAMetalLayer*)View.layer).drawableSize = CGSizeMake(InSizeX, InSizeY); #else + BackBuffer = (FMetalTexture2D*)(FTexture2DRHIParamRef)GDynamicRHI->RHICreateTexture2D(InSizeX, InSizeY, PF_B8G8R8A8, 1, 1, TexCreate_RenderTargetable | TexCreate_Presentable, CreateInfo); IOSAppDelegate* AppDelegate = [IOSAppDelegate GetDelegate]; FIOSView* GLView = AppDelegate.IOSView; [GLView UpdateRenderWidth:InSizeX andHeight:InSizeY]; @@ -104,6 +104,7 @@ void FMetalViewport::Resize(uint32 InSizeX, uint32 InSizeY, bool bInIsFullscreen check(FMath::TruncToInt(ScalingFactor * ViewFrame.size.width) == InSizeX && FMath::TruncToInt(ScalingFactor * ViewFrame.size.height) == InSizeY); #endif + BackBuffer->Surface.Viewport = this; } id FMetalViewport::GetDrawable() @@ -141,7 +142,9 @@ void FMetalViewport::ReleaseDrawable() [Drawable release]; Drawable = nil; } +#if !PLATFORM_MAC BackBuffer->Surface.Texture = nil; +#endif } #if PLATFORM_MAC @@ -186,6 +189,8 @@ void FMetalDynamicRHI::RHIBeginDrawingViewport(FViewportRHIParamRef ViewportRHI, { FMetalViewport* Viewport = ResourceCast(ViewportRHI); + check(Viewport); + ((FMetalDeviceContext*)Context)->BeginDrawingViewport(Viewport); // Set the render target and viewport. diff --git a/Engine/Source/Runtime/Apple/MetalRHI/Public/MetalViewport.h b/Engine/Source/Runtime/Apple/MetalRHI/Public/MetalViewport.h index 916cce9bb61c..3cac355ee0fb 100644 --- a/Engine/Source/Runtime/Apple/MetalRHI/Public/MetalViewport.h +++ b/Engine/Source/Runtime/Apple/MetalRHI/Public/MetalViewport.h @@ -19,7 +19,7 @@ public: ~FMetalViewport(); void Resize(uint32 InSizeX, uint32 InSizeY, bool bInIsFullscreen); - + FMetalTexture2D* GetBackBuffer() const { return BackBuffer; } id GetDrawable(); id GetDrawableTexture(); diff --git a/Engine/Source/Runtime/AssetRegistry/Private/AssetRegistryModule.cpp b/Engine/Source/Runtime/AssetRegistry/Private/AssetRegistryModule.cpp index a690a43a3c06..527b36cc88c7 100644 --- a/Engine/Source/Runtime/AssetRegistry/Private/AssetRegistryModule.cpp +++ b/Engine/Source/Runtime/AssetRegistry/Private/AssetRegistryModule.cpp @@ -5,27 +5,12 @@ #include "AssetRegistryModule.h" #include "AssetRegistryConsoleCommands.h" -#include "Developer/MessageLog/Public/MessageLogModule.h" - -#define LOCTEXT_NAMESPACE "AssetRegistry" - IMPLEMENT_MODULE( FAssetRegistryModule, AssetRegistry ); void FAssetRegistryModule::StartupModule() { AssetRegistry = new FAssetRegistry(); ConsoleCommands = new FAssetRegistryConsoleCommands(*this); - -#if WITH_UNREAL_DEVELOPER_TOOLS - // MessageLog needs EditorStyle to be loaded, and we might be being initialized before that has happened - FModuleManager::LoadModuleChecked("EditorStyle"); - - // create a message log for the asset registry to use - FMessageLogModule& MessageLogModule = FModuleManager::LoadModuleChecked("MessageLog"); - FMessageLogInitializationOptions InitOptions; - InitOptions.bShowPages = true; - MessageLogModule.RegisterLogListing("AssetRegistry", LOCTEXT("AssetRegistryLogLabel", "Asset Registry"), InitOptions); -#endif } @@ -42,15 +27,6 @@ void FAssetRegistryModule::ShutdownModule() delete ConsoleCommands; ConsoleCommands = NULL; } - -#if WITH_UNREAL_DEVELOPER_TOOLS - if( FModuleManager::Get().IsModuleLoaded("MessageLog") ) - { - // unregister message log - FMessageLogModule& MessageLogModule = FModuleManager::GetModuleChecked("MessageLog"); - MessageLogModule.UnregisterLogListing("AssetRegistry"); - } -#endif } IAssetRegistry& FAssetRegistryModule::Get() const @@ -58,5 +34,3 @@ IAssetRegistry& FAssetRegistryModule::Get() const check(AssetRegistry); return *AssetRegistry; } - -#undef LOCTEXT_NAMESPACE \ No newline at end of file diff --git a/Engine/Source/Runtime/Core/Private/Android/AndroidMisc.cpp b/Engine/Source/Runtime/Core/Private/Android/AndroidMisc.cpp index 1262a9827c88..51c01cf97872 100644 --- a/Engine/Source/Runtime/Core/Private/Android/AndroidMisc.cpp +++ b/Engine/Source/Runtime/Core/Private/Android/AndroidMisc.cpp @@ -601,12 +601,17 @@ const int32 TargetSignals[] = const int32 NumTargetSignals = ARRAY_COUNT(TargetSignals); struct sigaction PrevActions[NumTargetSignals]; +static bool PreviousSignalHandlersValid = false; static void RestorePreviousSignalHandlers() { - for (int32 i = 0; i < NumTargetSignals; ++i) + if (PreviousSignalHandlersValid) { - sigaction(TargetSignals[i], &PrevActions[i], NULL); + for (int32 i = 0; i < NumTargetSignals; ++i) + { + sigaction(TargetSignals[i], &PrevActions[i], NULL); + } + PreviousSignalHandlersValid = false; } } @@ -616,7 +621,6 @@ void PlatformCrashHandler(int32 Signal, siginfo* Info, void* Context) // Switch to malloc crash. //FGenericPlatformMallocCrash::Get().SetAsGMalloc(); @todo uncomment after verification - //fprintf(stderr, "Signal %d caught.\n", Signal); FPlatformMisc::LowLevelOutputDebugStringf(TEXT("Signal %d caught!"), Signal); // Restore system handlers so Android could catch this signal after we are done with crashreport @@ -640,8 +644,15 @@ void FAndroidMisc::SetCrashHandler(void (* CrashHandler)(const FGenericCrashCont { GCrashHandlerPointer = CrashHandler; + RestorePreviousSignalHandlers(); FMemory::Memzero(&PrevActions, sizeof(PrevActions)); + // Passing -1 will leave these restored and won't trap them + if ((int)CrashHandler == -1) + { + return; + } + struct sigaction Action; FMemory::Memzero(&Action, sizeof(struct sigaction)); Action.sa_sigaction = PlatformCrashHandler; @@ -652,6 +663,7 @@ void FAndroidMisc::SetCrashHandler(void (* CrashHandler)(const FGenericCrashCont { sigaction(TargetSignals[i], &Action, &PrevActions[i]); } + PreviousSignalHandlersValid = true; } bool FAndroidMisc::GetUseVirtualJoysticks() diff --git a/Engine/Source/Runtime/Core/Private/IOS/IOSPlatformFile.cpp b/Engine/Source/Runtime/Core/Private/IOS/IOSPlatformFile.cpp index 98a7daf9fc2e..78eeb0fcab2f 100644 --- a/Engine/Source/Runtime/Core/Private/IOS/IOSPlatformFile.cpp +++ b/Engine/Source/Runtime/Core/Private/IOS/IOSPlatformFile.cpp @@ -582,11 +582,7 @@ IFileHandle* FIOSPlatformFile::OpenRead(const TCHAR* Filename, bool bAllowWrite) IFileHandle* FIOSPlatformFile::OpenWrite(const TCHAR* Filename, bool bAppend, bool bAllowRead) { int Flags = O_CREAT; - if (bAppend) - { - Flags |= O_APPEND; - } - else + if (!bAppend) { Flags |= O_TRUNC; } diff --git a/Engine/Source/Runtime/Core/Public/Math/Transform.h b/Engine/Source/Runtime/Core/Public/Math/Transform.h index 511e81ad8db3..4ed3303cf02f 100644 --- a/Engine/Source/Runtime/Core/Public/Math/Transform.h +++ b/Engine/Source/Runtime/Core/Public/Math/Transform.h @@ -319,7 +319,8 @@ public: FORCEINLINE FTransform Inverse() const { FQuat InvRotation = Rotation.Inverse(); - FVector InvScale3D = Scale3D.Reciprocal(); + // this used to cause NaN if Scale contained 0 + FVector InvScale3D = GetSafeScaleReciprocal(Scale3D); FVector InvTranslation = InvRotation * (InvScale3D * -Translation); return FTransform(InvRotation, InvTranslation, InvScale3D); @@ -721,6 +722,18 @@ public: */ FORCEINLINE static void Multiply(FTransform* OutTransform, const FTransform* A, const FTransform* B); + /** + * Create a new transform: OutTransform = A * B using the matrix while keeping the scale that's given by A and B + * Please note that this operation is a lot more expensive than normal Multiply + * + * Order matters when composing transforms : A * B will yield a transform that logically first applies A then B to any subsequent transformation. + * + * @param OutTransform pointer to transform that will store the result of A * B. + * @param A Transform A. + * @param B Transform B. + */ + FORCEINLINE static void MultiplyUsingMatrixWithScale(FTransform* OutTransform, const FTransform* A, const FTransform* B); + /** * Sets the components * @param InRotation The new value for the Rotation component @@ -1195,14 +1208,47 @@ FORCEINLINE void FTransform::RemoveScaling(float Tolerance/*=SMALL_NUMBER*/) DiagnosticCheckNaN_Scale3D(); } +FORCEINLINE void FTransform::MultiplyUsingMatrixWithScale(FTransform* OutTransform, const FTransform* A, const FTransform* B) +{ + // the goal of using M is to get the correct orientation + // but for translation, we still need scale + FMatrix M = A->ToMatrixWithScale() * B->ToMatrixWithScale(); + M.RemoveScaling(); + + // get combined scale + FVector Scale3D = A->Scale3D*B->Scale3D; + + // apply negative scale back to axes + FVector SignedScale = Scale3D.GetSignVector(); + + M.SetAxis(0, SignedScale.X * M.GetScaledAxis(EAxis::X)); + M.SetAxis(1, SignedScale.Y * M.GetScaledAxis(EAxis::Y)); + M.SetAxis(2, SignedScale.Z * M.GetScaledAxis(EAxis::Z)); + + // @note: if you have negative with 0 scale, this will return rotation that is identity + // since matrix loses that axes + FQuat Rotation = FQuat(M); + Rotation.Normalize(); + + // set values back to output + OutTransform->Scale3D = Scale3D; + OutTransform->Rotation = Rotation; + + // technically I could calculate this using FTransform but then it does more quat multiplication + // instead of using Scale in matrix multiplication + // it's a question of between RemoveScaling vs using FTransform to move translation + OutTransform->Translation = M.GetOrigin(); +} + + /** Returns Multiplied Transform of 2 FTransforms **/ FORCEINLINE void FTransform::Multiply(FTransform* OutTransform, const FTransform* A, const FTransform* B) { A->DiagnosticCheckNaN_All(); B->DiagnosticCheckNaN_All(); - checkSlow( A->IsRotationNormalized() ); - checkSlow( B->IsRotationNormalized() ); + checkSlow(A->IsRotationNormalized()); + checkSlow(B->IsRotationNormalized()); // When Q = quaternion, S = single scalar scale, and T = translation // QST(A) = Q(A), S(A), T(A), and QST(B) = Q(B), S(B), T(B) @@ -1219,19 +1265,23 @@ FORCEINLINE void FTransform::Multiply(FTransform* OutTransform, const FTransform // S(AxB) = S(A)*S(B) // T(AxB) = Q(B)*S(B)*T(A)*-Q(B) + T(B) - FTransform Ret; - Ret.Rotation = B->Rotation*A->Rotation; + const bool bHaveNegativeScale = A->Scale3D.GetMin() < 0 || B->Scale3D.GetMin() < 0; + if (bHaveNegativeScale) + { + // @note, if you have 0 scale with negative, you're going to lose rotation as it can't convert back to quat + MultiplyUsingMatrixWithScale(OutTransform, A, B); + } + else + { + OutTransform->Rotation = B->Rotation*A->Rotation; + OutTransform->Scale3D = A->Scale3D*B->Scale3D; + OutTransform->Translation = B->Rotation*(B->Scale3D*A->Translation) + B->Translation; + } - Ret.Scale3D = A->Scale3D*B->Scale3D; - Ret.Translation = B->Rotation*(B->Scale3D*A->Translation) + B->Translation; // we do not support matrix transform when non-uniform // that was removed at rev 21 with UE4 - - *OutTransform = Ret; - Ret.DiagnosticCheckNaN_All(); + OutTransform->DiagnosticCheckNaN_All(); } - - /** * Apply Scale to this transform */ diff --git a/Engine/Source/Runtime/Core/Public/Math/TransformVectorized.h b/Engine/Source/Runtime/Core/Public/Math/TransformVectorized.h index 5cf000d9bea2..5cfd30e3823c 100644 --- a/Engine/Source/Runtime/Core/Public/Math/TransformVectorized.h +++ b/Engine/Source/Runtime/Core/Public/Math/TransformVectorized.h @@ -744,6 +744,18 @@ public: FORCEINLINE static void Multiply(FTransform* OutTransform, const FTransform* A, const FTransform* B); + /** + * Create a new transform: OutTransform = A * B using the matrix while keeping the scale that's given by A and B + * Please note that this operation is a lot more expensive than normal Multiply + * + * Order matters when composing transforms : A * B will yield a transform that logically first applies A then B to any subsequent transformation. + * + * @param OutTransform pointer to transform that will store the result of A * B. + * @param A Transform A. + * @param B Transform B. + */ + FORCEINLINE static void MultiplyUsingMatrixWithScale(FTransform* OutTransform, const FTransform* A, const FTransform* B); + /** * Sets the components * @param InRotation The new value for the Rotation component @@ -1411,14 +1423,48 @@ FORCEINLINE void FTransform::RemoveScaling(float Tolerance/*=SMALL_NUMBER*/) DiagnosticCheckNaN_Scale3D(); } +FORCEINLINE void FTransform::MultiplyUsingMatrixWithScale(FTransform* OutTransform, const FTransform* A, const FTransform* B) +{ + // the goal of using M is to get the correct orientation + // but for translation, we still need scale + FMatrix M = A->ToMatrixWithScale() * B->ToMatrixWithScale(); + M.RemoveScaling(); + + // get combined scale + const VectorRegister Scale3D = VectorMultiply(A->Scale3D, B->Scale3D); + + // apply negative scale back to axes + FVector SignedScale; + VectorStoreFloat3(VectorSign(Scale3D), &SignedScale); + + M.SetAxis(0, SignedScale.X * M.GetScaledAxis(EAxis::X)); + M.SetAxis(1, SignedScale.Y * M.GetScaledAxis(EAxis::Y)); + M.SetAxis(2, SignedScale.Z * M.GetScaledAxis(EAxis::Z)); + + // @note: if you have negative with 0 scale, this will return rotation that is identity + // since matrix loses that axes + FQuat Rotation = FQuat(M); + Rotation.Normalize(); + + // set values back to output + OutTransform->Scale3D = Scale3D; + OutTransform->Rotation = VectorLoadAligned(&Rotation); + + // technically I could calculate this using FTransform but then it does more quat multiplication + // instead of using Scale in matrix multiplication + // it's a question of between RemoveScaling vs using FTransform to move translation + FVector Translation = M.GetOrigin(); + OutTransform->Translation = VectorLoadFloat3_W0(&Translation); +} + /** Returns Multiplied Transform of 2 FTransforms **/ FORCEINLINE void FTransform::Multiply(FTransform* OutTransform, const FTransform* A, const FTransform* B) { A->DiagnosticCheckNaN_All(); B->DiagnosticCheckNaN_All(); - checkSlow( A->IsRotationNormalized() ); - checkSlow( B->IsRotationNormalized() ); + checkSlow(A->IsRotationNormalized()); + checkSlow(B->IsRotationNormalized()); // When Q = quaternion, S = single scalar scale, and T = translation // QST(A) = Q(A), S(A), T(A), and QST(B) = Q(B), S(B), T(B) @@ -1435,26 +1481,34 @@ FORCEINLINE void FTransform::Multiply(FTransform* OutTransform, const FTransform // S(AxB) = S(A)*S(B) // T(AxB) = Q(B)*S(B)*T(A)*-Q(B) + T(B) - const VectorRegister QuatA = A->Rotation; - const VectorRegister QuatB = B->Rotation; - const VectorRegister TranslateA = A->Translation; - const VectorRegister TranslateB = B->Translation; - const VectorRegister ScaleA = A->Scale3D; - const VectorRegister ScaleB = B->Scale3D; + const VectorRegister MinVector = VectorMin(A->Scale3D, B->Scale3D); + const bool bHaveNegativeScale = VectorGetComponent(MinVector, 0) < 0.f || VectorGetComponent(MinVector, 1) < 0.f || VectorGetComponent(MinVector, 2) < 0.f; + if (bHaveNegativeScale) + { + // @note, if you have 0 scale with negative, you're going to lose rotation as it can't convert back to quat + MultiplyUsingMatrixWithScale(OutTransform, A, B); + } + else + { + const VectorRegister QuatA = A->Rotation; + const VectorRegister QuatB = B->Rotation; + const VectorRegister TranslateA = A->Translation; + const VectorRegister TranslateB = B->Translation; + const VectorRegister ScaleA = A->Scale3D; + const VectorRegister ScaleB = B->Scale3D; - // RotationResult = B.Rotation * A.Rotation - OutTransform->Rotation = VectorQuaternionMultiply2(QuatB, QuatA); + // RotationResult = B.Rotation * A.Rotation + OutTransform->Rotation = VectorQuaternionMultiply2(QuatB, QuatA); - // TranslateResult = B.Rotate(B.Scale * A.Translation) + B.Translate - const VectorRegister ScaledTransA = VectorMultiply(TranslateA, ScaleB); - const VectorRegister RotatedTranslate = VectorQuaternionRotateVector(QuatB, ScaledTransA); - OutTransform->Translation = VectorAdd(RotatedTranslate, TranslateB); - - // ScaleResult = Scale.B * Scale.A - OutTransform->Scale3D = VectorMultiply(ScaleA, ScaleB);; + // TranslateResult = B.Rotate(B.Scale * A.Translation) + B.Translate + const VectorRegister ScaledTransA = VectorMultiply(TranslateA, ScaleB); + const VectorRegister RotatedTranslate = VectorQuaternionRotateVector(QuatB, ScaledTransA); + OutTransform->Translation = VectorAdd(RotatedTranslate, TranslateB); + // ScaleResult = Scale.B * Scale.A + OutTransform->Scale3D = VectorMultiply(ScaleA, ScaleB);; + } } - /** * Apply Scale to this transform */ diff --git a/Engine/Source/Runtime/Core/Public/UObject/FrameworkObjectVersion.h b/Engine/Source/Runtime/Core/Public/UObject/FrameworkObjectVersion.h index 570ab1b8dc44..0f8223de3f3a 100644 --- a/Engine/Source/Runtime/Core/Public/UObject/FrameworkObjectVersion.h +++ b/Engine/Source/Runtime/Core/Public/UObject/FrameworkObjectVersion.h @@ -25,6 +25,10 @@ struct CORE_API FFrameworkObjectVersion // Moved compressed anim data from uasset to the DDC MoveCompressedAnimDataToTheDDC, + // Some graph pins created using legacy code seem to have lost the RF_Transactional flag, + // which causes issues with undo. Restore the flag at this version + FixNonTransactionalPins, + // ------------------------------------------------------ VersionPlusOne, LatestVersion = VersionPlusOne - 1 diff --git a/Engine/Source/Runtime/CoreUObject/Private/Internationalization/PackageLocalizationManager.cpp b/Engine/Source/Runtime/CoreUObject/Private/Internationalization/PackageLocalizationManager.cpp index 8418114f2116..f798bfc0f8d1 100644 --- a/Engine/Source/Runtime/CoreUObject/Private/Internationalization/PackageLocalizationManager.cpp +++ b/Engine/Source/Runtime/CoreUObject/Private/Internationalization/PackageLocalizationManager.cpp @@ -38,6 +38,25 @@ void FDefaultPackageLocalizationCache::FindLocalizedPackages(const FString& InSo })); } +void FPackageLocalizationManager::PerformLazyInitialization() +{ + if (!ActiveCache.IsValid() && LazyInitFunc) + { + LazyInitFunc(*this); + + if (!ActiveCache.IsValid()) + { + UE_LOG(LogPackageLocalizationManager, Warning, TEXT("InitializeFromLazyCallback was bound to a callback that didn't initialize the active cache.")); + } + } +} + +void FPackageLocalizationManager::InitializeFromLazyCallback(FLazyInitFunc InLazyInitFunc) +{ + LazyInitFunc = MoveTemp(InLazyInitFunc); + ActiveCache.Reset(); +} + void FPackageLocalizationManager::InitializeFromCache(const TSharedRef& InCache) { ActiveCache = InCache; @@ -50,8 +69,10 @@ void FPackageLocalizationManager::InitializeFromDefaultCache() ActiveCache->ConditionalUpdateCache(); } -FName FPackageLocalizationManager::FindLocalizedPackageName(const FName InSourcePackageName) const +FName FPackageLocalizationManager::FindLocalizedPackageName(const FName InSourcePackageName) { + PerformLazyInitialization(); + if (ActiveCache.IsValid()) { return ActiveCache->FindLocalizedPackageName(InSourcePackageName); @@ -62,8 +83,10 @@ FName FPackageLocalizationManager::FindLocalizedPackageName(const FName InSource return FindLocalizedPackageNameNoCache(InSourcePackageName, CurrentCultureName); } -FName FPackageLocalizationManager::FindLocalizedPackageNameForCulture(const FName InSourcePackageName, const FString& InCultureName) const +FName FPackageLocalizationManager::FindLocalizedPackageNameForCulture(const FName InSourcePackageName, const FString& InCultureName) { + PerformLazyInitialization(); + if (ActiveCache.IsValid()) { return ActiveCache->FindLocalizedPackageNameForCulture(InSourcePackageName, InCultureName); diff --git a/Engine/Source/Runtime/CoreUObject/Private/Internationalization/PackageLocalizationUtil.cpp b/Engine/Source/Runtime/CoreUObject/Private/Internationalization/PackageLocalizationUtil.cpp new file mode 100644 index 000000000000..24e966148ace --- /dev/null +++ b/Engine/Source/Runtime/CoreUObject/Private/Internationalization/PackageLocalizationUtil.cpp @@ -0,0 +1,71 @@ +// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. + +#include "CoreUObjectPrivate.h" +#include "PackageLocalizationUtil.h" + +bool FPackageLocalizationUtil::ConvertLocalizedToSource(const FString& InLocalized, FString& OutSource) +{ + if (FPackageName::IsLocalizedPackage(InLocalized)) + { + const int32 L10NStart = InLocalized.Find(TEXT("L10N"), ESearchCase::IgnoreCase); + if (L10NStart != INDEX_NONE) + { + // /Game/L10N/fr/Folder/MyAsset + // ^ We matched here, so we need to walk over the L10N folder, and then walk over the culture code to find the range of characters to remove + int32 NumSlashesToFind = 2; + int32 L10NEnd = L10NStart; + for (; L10NEnd < InLocalized.Len() && NumSlashesToFind > 0; ++L10NEnd) + { + if (InLocalized[L10NEnd] == TEXT('/')) + { + --NumSlashesToFind; + } + } + + OutSource = InLocalized; + OutSource.RemoveAt(L10NStart, L10NEnd - L10NStart, false); + return true; + } + } + + return false; +} + +bool FPackageLocalizationUtil::ConvertSourceToLocalized(const FString& InSource, const FString& InCulture, FString& OutLocalized) +{ + if (!FPackageName::IsLocalizedPackage(InSource)) + { + if (InSource.Len() > 0 && InSource[0] == TEXT('/')) + { + const int32 RootPathEnd = InSource.Find(TEXT("/"), ESearchCase::IgnoreCase, ESearchDir::FromStart, 1); + if (RootPathEnd != INDEX_NONE) + { + OutLocalized = InSource; + OutLocalized.InsertAt(RootPathEnd, TEXT("/L10N") / InCulture); + return true; + } + } + } + + return false; +} + +bool FPackageLocalizationUtil::GetLocalizedRoot(const FString& InPath, const FString& InCulture, FString& OutLocalized) +{ + if (InPath.Len() > 0 && InPath[0] == TEXT('/')) + { + const int32 RootPathEnd = InPath.Find(TEXT("/"), ESearchCase::IgnoreCase, ESearchDir::FromStart, 1); + if (RootPathEnd != INDEX_NONE) + { + OutLocalized = InPath.Left(RootPathEnd); + OutLocalized /= TEXT("L10N"); + if (InCulture.Len() > 0) + { + OutLocalized /= InCulture; + } + return true; + } + } + + return false; +} diff --git a/Engine/Source/Runtime/CoreUObject/Private/UObject/UObjectGlobals.cpp b/Engine/Source/Runtime/CoreUObject/Private/UObject/UObjectGlobals.cpp index 40349f5c3be1..a26aa0a446ca 100644 --- a/Engine/Source/Runtime/CoreUObject/Private/UObject/UObjectGlobals.cpp +++ b/Engine/Source/Runtime/CoreUObject/Private/UObject/UObjectGlobals.cpp @@ -2761,8 +2761,8 @@ void FObjectInitializer::InitProperties(UObject* Obj, UClass* DefaultsClass, UOb { // @TODO: temporarily disabling the PostConstructLink optimization here // since it is unknowingly causing issues in gameplay (see - // UE-28522) - we're still unclear on what specifically this is - // doing wrong, but will investigate (UE-29449) + // UE-29940) - we're still unclear on what specifically this is + // doing wrong, but will investigate (UE-30120) bCanUsePostConstructLink = false; QUICK_SCOPE_CYCLE_COUNTER(STAT_InitProperties_Blueprint); @@ -2838,15 +2838,24 @@ void FObjectInitializer::InitArrayPropertyFromCustomList(const UArrayProperty* A FScriptArrayHelper DstArrayValueHelper(ArrayProperty, DataPtr); FScriptArrayHelper SrcArrayValueHelper(ArrayProperty, DefaultDataPtr); - int32 Num = SrcArrayValueHelper.Num(); + const int32 SrcNum = SrcArrayValueHelper.Num(); + const int32 DstNum = DstArrayValueHelper.Num(); - if (!(ArrayProperty->Inner->PropertyFlags & CPF_IsPlainOldData)) + if (SrcNum > DstNum) { - DstArrayValueHelper.EmptyAndAddValues(Num); + const int32 Count = SrcNum - DstNum; + if (!(ArrayProperty->Inner->PropertyFlags & CPF_IsPlainOldData)) + { + DstArrayValueHelper.AddValues(Count); + } + else + { + DstArrayValueHelper.AddUninitializedValues(Count); + } } - else + else if (SrcNum < DstNum) { - DstArrayValueHelper.EmptyAndAddUninitializedValues(Num); + DstArrayValueHelper.RemoveValues(SrcNum, DstNum - SrcNum); } for (const FCustomPropertyListNode* CustomArrayPropertyListNode = InPropertyList; CustomArrayPropertyListNode; CustomArrayPropertyListNode = CustomArrayPropertyListNode->PropertyListNext) @@ -2856,24 +2865,7 @@ void FObjectInitializer::InitArrayPropertyFromCustomList(const UArrayProperty* A uint8* DstArrayItemValue = DstArrayValueHelper.GetRawPtr(ArrayIndex); const uint8* SrcArrayItemValue = SrcArrayValueHelper.GetRawPtr(ArrayIndex); - // A null property value signals that we should serialize the remaining array values in full starting at this index - if (CustomArrayPropertyListNode->Property == nullptr) - { - int32 Size = ArrayProperty->Inner->ElementSize; - - if (!(ArrayProperty->Inner->PropertyFlags & CPF_IsPlainOldData)) - { - for (int32 i = 0; i < Num - ArrayIndex; i++) - { - ArrayProperty->Inner->CopyCompleteValue(DstArrayItemValue + i * Size, SrcArrayItemValue + i * Size); - } - } - else - { - FMemory::Memcpy(DstArrayItemValue, SrcArrayItemValue, (Num - ArrayIndex) * Size); - } - } - else if (const UStructProperty* InnerStructProperty = Cast(ArrayProperty->Inner)) + if (const UStructProperty* InnerStructProperty = Cast(ArrayProperty->Inner)) { InitPropertiesFromCustomList(CustomArrayPropertyListNode->SubPropertyList, InnerStructProperty->Struct, DstArrayItemValue, SrcArrayItemValue); } diff --git a/Engine/Source/Runtime/CoreUObject/Public/Internationalization/PackageLocalizationManager.h b/Engine/Source/Runtime/CoreUObject/Public/Internationalization/PackageLocalizationManager.h index b86108abc298..366426b8d69e 100644 --- a/Engine/Source/Runtime/CoreUObject/Public/Internationalization/PackageLocalizationManager.h +++ b/Engine/Source/Runtime/CoreUObject/Public/Internationalization/PackageLocalizationManager.h @@ -8,6 +8,20 @@ class IPackageLocalizationCache; class COREUOBJECT_API FPackageLocalizationManager { public: + typedef TFunction FLazyInitFunc; + + /** + * Initialize the manager from the callback set by InitializeFromLazyCallback. It is expected that this callback calls one of the InitializeFromX functions. + */ + void PerformLazyInitialization(); + + /** + * Initialize the manager lazily using the given callback. It is expected that this callback calls one of the InitializeFromX functions. + * + * @param InLazyInitFunc The function to call to initialize the manager. + */ + void InitializeFromLazyCallback(FLazyInitFunc InLazyInitFunc); + /** * Initialize the manager using the given cache. This will perform an initial scan for localized packages. * @@ -27,7 +41,7 @@ public: * * @return The localized package name, or NAME_None if there is no localized package. */ - FName FindLocalizedPackageName(const FName InSourcePackageName) const; + FName FindLocalizedPackageName(const FName InSourcePackageName); /** * Try and find the localized package name for the given source package for the given culture. @@ -37,7 +51,7 @@ public: * * @return The localized package name, or NAME_None if there is no localized package. */ - FName FindLocalizedPackageNameForCulture(const FName InSourcePackageName, const FString& InCultureName) const; + FName FindLocalizedPackageNameForCulture(const FName InSourcePackageName, const FString& InCultureName); /** * Singleton accessor. @@ -57,6 +71,9 @@ private: */ FName FindLocalizedPackageNameNoCache(const FName InSourcePackageName, const FString& InCultureName) const; + /** Function to call to lazily initialize the manager. */ + FLazyInitFunc LazyInitFunc; + /** Pointer to our currently active cache. Only valid after Initialize has been called. */ TSharedPtr ActiveCache; }; diff --git a/Engine/Source/Runtime/CoreUObject/Public/Internationalization/PackageLocalizationUtil.h b/Engine/Source/Runtime/CoreUObject/Public/Internationalization/PackageLocalizationUtil.h new file mode 100644 index 000000000000..1084a94e9371 --- /dev/null +++ b/Engine/Source/Runtime/CoreUObject/Public/Internationalization/PackageLocalizationUtil.h @@ -0,0 +1,41 @@ +// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. + +#pragma once + +/** Utility functions for dealing with localized package names */ +struct COREUOBJECT_API FPackageLocalizationUtil +{ + /** + * Converts a localized version of a package path to the source version (by removing /L10N/ from the package path, if present) + * Note: This does not check whether the source package exists + * + * @param InLocalized Path to the localized package. + * @param OutSource Path to the source package. + * + * @returns True if the conversion happened, false otherwise + */ + static bool ConvertLocalizedToSource(const FString& InLocalized, FString& OutSource); + + /** + * Converts a source version of a package path to the localized version for the given culture (by adding /L10N/ to the package path) + * Note: This does not check whether the source package exists + * + * @param InSource Path to the source package. + * @param InCulture Culture code to use. + * @param OutLocalized Path to the localized package. + * + * @returns True if the conversion happened, false otherwise + */ + static bool ConvertSourceToLocalized(const FString& InSource, const FString& InCulture, FString& OutLocalized); + + /** + * Given a package path, get the localized root package for the given culture (eg, if given "/Game/MyFolder/MyAsset" and a culture of "fr", this would return "/Game/L10N/fr") + * + * @param InPath Package path to use. + * @param InCulture Culture code to use (if any). + * @param OutLocalized Localized package root. + * + * @returns True if the conversion happened, false otherwise + */ + static bool GetLocalizedRoot(const FString& InPath, const FString& InCulture, FString& OutLocalized); +}; diff --git a/Engine/Source/Runtime/Engine/Classes/Animation/AnimComposite.h b/Engine/Source/Runtime/Engine/Classes/Animation/AnimComposite.h index 911b93e99b6b..ba35d729a8d0 100644 --- a/Engine/Source/Runtime/Engine/Classes/Animation/AnimComposite.h +++ b/Engine/Source/Runtime/Engine/Classes/Animation/AnimComposite.h @@ -32,6 +32,8 @@ public: virtual bool IsValidAdditive() const override { return GetAdditiveAnimType() != AAT_None; } virtual void EnableRootMotionSettingFromMontage(bool bInEnableRootMotion, const ERootMotionRootLock::Type InRootMotionRootLock) override; virtual bool HasRootMotion() const override; + virtual void GetAnimNotifiesFromDeltaPositions(const float& PreviousPosition, const float & CurrentPosition, TArray& OutActiveNotifies) const override; + virtual bool IsNotifyAvailable() const override; //~ End UAnimSequenceBase Interface //~ Begin UAnimSequence Interface #if WITH_EDITOR diff --git a/Engine/Source/Runtime/Engine/Classes/Animation/AnimCompositeBase.h b/Engine/Source/Runtime/Engine/Classes/Animation/AnimCompositeBase.h index c6a75cf26d2d..585bfab009b8 100644 --- a/Engine/Source/Runtime/Engine/Classes/Animation/AnimCompositeBase.h +++ b/Engine/Source/Runtime/Engine/Classes/Animation/AnimCompositeBase.h @@ -159,6 +159,11 @@ struct FAnimSegment * return true if valid, false otherwise, only invalid if we contains recursive reference **/ bool IsValid() const { return bValid; } + + /** + * return true if anim notify is available + */ + bool IsNotifyAvailable() const { return IsValid() && AnimReference && AnimReference->IsNotifyAvailable(); } private: /** @@ -249,6 +254,8 @@ struct FAnimTrack */ void GetAnimNotifiesFromTrackPositions(const float& PreviousTrackPosition, const float& CurrentTrackPosition, TArray & OutActiveNotifies) const; + /** return true if anim notify is available */ + bool IsNotifyAvailable() const; }; UCLASS(abstract, MinimalAPI) diff --git a/Engine/Source/Runtime/Engine/Classes/Animation/AnimInstance.h b/Engine/Source/Runtime/Engine/Classes/Animation/AnimInstance.h index 8c994282c066..d798b03f7ef5 100644 --- a/Engine/Source/Runtime/Engine/Classes/Animation/AnimInstance.h +++ b/Engine/Source/Runtime/Engine/Classes/Animation/AnimInstance.h @@ -1022,6 +1022,9 @@ public: /** Called after updates are completed, dispatches notifies etc. */ void PostUpdateAnimation(); + /** Called on the game thread pre-evaluation. */ + void PreEvaluateAnimation(); + DEPRECATED(4.11, "This function should no longer be used. Use ParallelEvaluateAnimation") void EvaluateAnimation(struct FPoseContext& Output); diff --git a/Engine/Source/Runtime/Engine/Classes/Animation/AnimMontage.h b/Engine/Source/Runtime/Engine/Classes/Animation/AnimMontage.h index 92c231805cae..eb52e4cf3c64 100644 --- a/Engine/Source/Runtime/Engine/Classes/Animation/AnimMontage.h +++ b/Engine/Source/Runtime/Engine/Classes/Animation/AnimMontage.h @@ -35,7 +35,6 @@ struct FCompositeSection : public FAnimLinkableElement UPROPERTY() FName NextSectionName; -private: /** Meta data that can be saved with the asset * * You can query by GetMetaData function diff --git a/Engine/Source/Runtime/Engine/Classes/Animation/AnimSequenceBase.h b/Engine/Source/Runtime/Engine/Classes/Animation/AnimSequenceBase.h index 9d5094784d66..6a2c2ad651cf 100644 --- a/Engine/Source/Runtime/Engine/Classes/Animation/AnimSequenceBase.h +++ b/Engine/Source/Runtime/Engine/Classes/Animation/AnimSequenceBase.h @@ -78,7 +78,7 @@ class UAnimSequenceBase : public UAnimationAsset * Supports playing backwards (CurrentPosition& OutActiveNotifies) const; + ENGINE_API virtual void GetAnimNotifiesFromDeltaPositions(const float& PreviousPosition, const float & CurrentPosition, TArray& OutActiveNotifies) const; /** Evaluate curve data to Instance at the time of CurrentTime **/ ENGINE_API virtual void EvaluateCurveData(FBlendedCurve& OutCurve, float CurrentTime, bool bForceUseRawData=false) const; @@ -181,6 +181,8 @@ public: virtual class UAnimSequence* GetAdditiveBasePose() const { return nullptr; } #endif + // return true if anim notify is available + virtual bool IsNotifyAvailable() const; protected: template diff --git a/Engine/Source/Runtime/Engine/Classes/Animation/AnimSingleNodeInstance.h b/Engine/Source/Runtime/Engine/Classes/Animation/AnimSingleNodeInstance.h index 8bba5f8507ca..bba4d023d39d 100644 --- a/Engine/Source/Runtime/Engine/Classes/Animation/AnimSingleNodeInstance.h +++ b/Engine/Source/Runtime/Engine/Classes/Animation/AnimSingleNodeInstance.h @@ -23,10 +23,10 @@ class ENGINE_API UAnimSingleNodeInstance : public UAnimInstance PRAGMA_ENABLE_DEPRECATION_WARNINGS /** Current Asset being played **/ - DEPRECATED(4.11, "Please use FAnimSingleNodeInstanceProxy::CurrentAsset") + UPROPERTY(Transient) class UAnimationAsset* CurrentAsset; - DEPRECATED(4.11, "Please use FAnimSingleNodeInstanceProxy::CurrentVertexAnim") + UPROPERTY(Transient) class UVertexAnimation* CurrentVertexAnim; /** Random cached values to play each asset **/ diff --git a/Engine/Source/Runtime/Engine/Classes/Components/ChildActorComponent.h b/Engine/Source/Runtime/Engine/Classes/Components/ChildActorComponent.h index 76ce23c1c50c..7926e47dae5f 100644 --- a/Engine/Source/Runtime/Engine/Classes/Components/ChildActorComponent.h +++ b/Engine/Source/Runtime/Engine/Classes/Components/ChildActorComponent.h @@ -50,7 +50,7 @@ private: TSubclassOf ChildActorClass; /** The actor that we spawned and own */ - UPROPERTY(BlueprintReadOnly, Category=ChildActorComponent, TextExportTransient, NonPIEDuplicateTransient, meta=(AllowPrivateAccess="true")) + UPROPERTY(Replicated, BlueprintReadOnly, Category=ChildActorComponent, TextExportTransient, NonPIEDuplicateTransient, meta=(AllowPrivateAccess="true")) AActor* ChildActor; /** We try to keep the child actor's name as best we can, so we store it off here when destroying */ @@ -68,6 +68,8 @@ public: virtual void PostLoad() override; #endif virtual void BeginDestroy() override; + virtual void GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const override; + virtual void PostRepNotifies() override; //~ End Object Interface. //~ Begin ActorComponent Interface. @@ -89,7 +91,7 @@ public: FName GetChildActorName() const { return ChildActorName; } /** Kill any currently present child actor */ - void DestroyChildActor(const bool bRequiresRename = true); + void DestroyChildActor(); }; diff --git a/Engine/Source/Runtime/Engine/Classes/Components/SceneComponent.h b/Engine/Source/Runtime/Engine/Classes/Components/SceneComponent.h index 6cfc76b09efc..412d7d427822 100644 --- a/Engine/Source/Runtime/Engine/Classes/Components/SceneComponent.h +++ b/Engine/Source/Runtime/Engine/Classes/Components/SceneComponent.h @@ -258,6 +258,8 @@ private: UFUNCTION() void OnRep_Visibility(bool OldValue); +protected: + virtual void PreNetReceive() override; virtual void PostNetReceive() override; virtual void PostRepNotifies() override; diff --git a/Engine/Source/Runtime/Engine/Classes/Components/SkeletalMeshComponent.h b/Engine/Source/Runtime/Engine/Classes/Components/SkeletalMeshComponent.h index e254920eb776..0337a4c63b7b 100644 --- a/Engine/Source/Runtime/Engine/Classes/Components/SkeletalMeshComponent.h +++ b/Engine/Source/Runtime/Engine/Classes/Components/SkeletalMeshComponent.h @@ -940,6 +940,8 @@ protected: virtual bool ComponentOverlapComponentImpl(class UPrimitiveComponent* PrimComp, const FVector Pos, const FQuat& Quat, const FCollisionQueryParams& Params) override; + virtual bool MoveComponentImpl(const FVector& Delta, const FQuat& NewRotation, bool bSweep, FHitResult* OutHit = NULL, EMoveComponentFlags MoveFlags = MOVECOMP_NoFlags, ETeleportType Teleport = ETeleportType::None) override; + public: virtual class UBodySetup* GetBodySetup() override; diff --git a/Engine/Source/Runtime/Engine/Classes/Components/SplineComponent.h b/Engine/Source/Runtime/Engine/Classes/Components/SplineComponent.h index 6c9d9d066e40..5e52b42170a8 100644 --- a/Engine/Source/Runtime/Engine/Classes/Components/SplineComponent.h +++ b/Engine/Source/Runtime/Engine/Classes/Components/SplineComponent.h @@ -76,11 +76,16 @@ class ENGINE_API USplineComponent : public UPrimitiveComponent UPROPERTY(EditAnywhere, Category = Spline, meta=(DisplayName="Override Construction Script")) bool bSplineHasBeenEdited; + /** + * Whether the spline points should be passed to the User Construction Script so they can be further manipulated by it. + * If false, they will not be visible to it, and it will not be able to influence the per-instance positions set in the editor. + */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Spline) bool bInputSplinePointsToConstructionScript; + /** If true, the spline will be rendered if the Splines showflag is set. */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Spline) - bool bAlwaysRenderInEditor; + bool bDrawDebug; private: /** @@ -94,16 +99,16 @@ public: /** Default up vector in local space to be used when calculating transforms along the spline */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Spline) FVector DefaultUpVector; - -#if WITH_EDITORONLY_DATA +#if !UE_BUILD_SHIPPING /** Color of an unselected spline component segment in the editor */ UPROPERTY(EditAnywhere, Category = Editor) FLinearColor EditorUnselectedSplineSegmentColor; - /** Color of a selected spline component segment in the editor */ UPROPERTY(EditAnywhere, Category = Editor) FLinearColor EditorSelectedSplineSegmentColor; +#endif +#if WITH_EDITORONLY_DATA /** Whether scale visualization should be displayed */ UPROPERTY(EditAnywhere, Category = Editor) bool bShouldVisualizeScale; @@ -126,7 +131,7 @@ public: virtual FActorComponentInstanceData* GetComponentInstanceData() const override; //~ End UActorComponent Interface. -#if WITH_EDITOR +#if !UE_BUILD_SHIPPING //~ Begin UPrimitiveComponent Interface. virtual FPrimitiveSceneProxy* CreateSceneProxy() override; //~ End UPrimitiveComponent Interface. @@ -183,6 +188,10 @@ public: UFUNCTION(BlueprintCallable, Category = Editor) void SetSelectedSplineSegmentColor(const FLinearColor& SegmentColor); + /** Specify whether this spline should be rendered when the Editor/Game spline show flag is set */ + UFUNCTION(BlueprintCallable, Category = Spline) + void SetDrawDebug(bool bShow); + /** Specify whether the spline is a closed loop or not */ UFUNCTION(BlueprintCallable, Category = Spline) void SetClosedLoop(bool bInClosedLoop); diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/BlueprintGeneratedClass.h b/Engine/Source/Runtime/Engine/Classes/Engine/BlueprintGeneratedClass.h index d0ddf4a51a3b..1b07d1317163 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/BlueprintGeneratedClass.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/BlueprintGeneratedClass.h @@ -696,7 +696,7 @@ protected: void BuildCustomPropertyListForPostConstruction(FCustomPropertyListNode*& InPropertyList, UStruct* InStruct, const uint8* DataPtr, const uint8* DefaultDataPtr); /** Internal helper method used to recursively build a custom property list from an array property used for post-construct initialization. */ - void BuildCustomArrayPropertyListForPostConstruction(UArrayProperty* ArrayProperty, FCustomPropertyListNode*& InPropertyList, const uint8* DataPtr, const uint8* DefaultDataPtr); + void BuildCustomArrayPropertyListForPostConstruction(UArrayProperty* ArrayProperty, FCustomPropertyListNode*& InPropertyList, const uint8* DataPtr, const uint8* DefaultDataPtr, int32 StartIndex = 0); private: /** List of native class-owned properties that differ from defaults. This is used to optimize property initialization during post-construction by minimizing the number of native class-owned property values that get copied to the new instance. */ diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/DemoNetDriver.h b/Engine/Source/Runtime/Engine/Classes/Engine/DemoNetDriver.h index 4c90370b459c..e50986c41fa0 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/DemoNetDriver.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/DemoNetDriver.h @@ -245,4 +245,7 @@ public: /** Called when a "go to time" operation is completed. */ void NotifyGotoTimeFinished(bool bWasSuccessful); + + /** Read the streaming level information from the metadata after the level is loaded */ + void PendingNetGameLoadMapCompleted(); }; diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/DemoPendingNetGame.h b/Engine/Source/Runtime/Engine/Classes/Engine/DemoPendingNetGame.h index be3799fea4cf..f3a0b56b28dd 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/DemoPendingNetGame.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/DemoPendingNetGame.h @@ -4,10 +4,17 @@ #include "DemoPendingNetGame.generated.h" +class UEngine; +struct FWorldContext; UCLASS(transient, config=Engine) class UDemoPendingNetGame : public UPendingNetGame { GENERATED_UCLASS_BODY() + + // UPendingNetGame interface. + virtual void Tick( float DeltaTime ) override; + virtual void SendJoin() override; + virtual void LoadMapCompleted(UEngine* Engine, FWorldContext& Context, bool bLoadedMapSuccessfully, const FString& LoadMapError) override; }; diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/GameViewportClient.h b/Engine/Source/Runtime/Engine/Classes/Engine/GameViewportClient.h index c48f2bc8b5b6..04b43cd026a4 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/GameViewportClient.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/GameViewportClient.h @@ -810,9 +810,6 @@ private: /** Those sound stat flags which are enabled on this viewport */ static ESoundShowFlags::Type SoundShowFlags; - /** Number of viewports which have enabled 'show collision' */ - static int32 NumViewportsShowingCollision; - /** Disables splitscreen, useful when game code is in menus, and doesn't want splitscreen on */ bool bDisableSplitScreenOverride; @@ -828,9 +825,6 @@ private: /** Whether or not the cursor is hidden when the viewport captures the mouse */ bool bHideCursorDuringCapture; - /** Handle to the registered ShowCollisionOnSpawnedActors delegate */ - FDelegateHandle ShowCollisionOnSpawnedActorsDelegateHandle; - /** Handle to the audio device created for this viewport. Each viewport (for multiple PIE) will have its own audio device. */ uint32 AudioDeviceHandle; diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/PendingNetGame.h b/Engine/Source/Runtime/Engine/Classes/Engine/PendingNetGame.h index 321338bf3dda..9a52f76eaf30 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/PendingNetGame.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/PendingNetGame.h @@ -3,6 +3,9 @@ #pragma once #include "PendingNetGame.generated.h" +struct FWorldContext; +class UEngine; + /** * Accepting connection response codes */ @@ -135,4 +138,7 @@ public: /** Create the peer net driver and a socket to listen for new client peer connections. */ void InitPeerListen(); + + /** Called by the engine after it calls LoadMap for this PendingNetGame. */ + virtual void LoadMapCompleted(UEngine* Engine, FWorldContext& Context, bool bLoadedMapSuccessfully, const FString& LoadMapError); }; diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/RendererSettings.h b/Engine/Source/Runtime/Engine/Classes/Engine/RendererSettings.h index 67ba1225a185..549563a2d41d 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/RendererSettings.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/RendererSettings.h @@ -164,6 +164,12 @@ class ENGINE_API URendererSettings : public UDeveloperSettings ConfigRestartRequired=true)) uint32 bUseDXT5NormalMaps:1; + UPROPERTY(config, EditAnywhere, Category = Materials, meta =( + ConfigRestartRequired = true, + ConsoleVariable = "r.ClearCoatNormal", + ToolTip = "Use a separate normal map for the bottom layer of a clear coat material. This is a higher quality feature that is expensive.")) + uint32 bClearCoatEnableSecondNormal : 1; + UPROPERTY(config, EditAnywhere, Category = Textures, meta = ( ConsoleVariable = "r.ReflectionCaptureResolution", DisplayName = "Reflection Capture Resolution", ToolTip = "The cubemap resolution for all reflection capture probes. Must be power of 2.")) diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/World.h b/Engine/Source/Runtime/Engine/Classes/Engine/World.h index acb83e3e0a84..8601974bfae7 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/World.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/World.h @@ -898,10 +898,10 @@ public: * You need Physics Scene if you'd like to trace. This flag changed ticking */ bool bShouldSimulatePhysics; -#if WITH_EDITOR /** If TRUE, 'hidden' components will still create render proxy, so can draw info (see USceneComponent::ShouldRender) */ bool bCreateRenderStateForHiddenComponents; +#if WITH_EDITOR /** this is special flag to enable collision by default for components that are not Volume * currently only used by editor level viewport world, and do not use this for in-game scene */ diff --git a/Engine/Source/Runtime/Engine/Classes/GameFramework/Actor.h b/Engine/Source/Runtime/Engine/Classes/GameFramework/Actor.h index 12ea126f3983..e5a9098887de 100644 --- a/Engine/Source/Runtime/Engine/Classes/GameFramework/Actor.h +++ b/Engine/Source/Runtime/Engine/Classes/GameFramework/Actor.h @@ -2322,9 +2322,6 @@ public: */ void ExecuteConstruction(const FTransform& Transform, const class FComponentInstanceDataCache* InstanceDataCache, bool bIsDefaultTransform = false); - // Forces PostLoad call on natively created components, that were originally in SCS - virtual void FixComponentsFromDynamicClass(); - /** * Called when an instance of this class is placed (in editor) or spawned. * @param Transform The transform the actor was constructed at. @@ -2718,6 +2715,12 @@ public: */ void UpdateAllReplicatedComponents(); + /** Returns whether replication is enabled or not. */ + FORCEINLINE bool GetIsReplicated() const + { + return bReplicates; + } + /** Returns a constant reference to the replicated components set */ const TSet& GetReplicatedComponents() const diff --git a/Engine/Source/Runtime/Engine/Classes/Materials/MaterialExpressionClearCoatNormalCustomOutput.h b/Engine/Source/Runtime/Engine/Classes/Materials/MaterialExpressionClearCoatNormalCustomOutput.h new file mode 100644 index 000000000000..0e388898bc74 --- /dev/null +++ b/Engine/Source/Runtime/Engine/Classes/Materials/MaterialExpressionClearCoatNormalCustomOutput.h @@ -0,0 +1,39 @@ +// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved. + + +#pragma once + +#include "Materials/MaterialExpressionCustomOutput.h" +#include "MaterialExpressionClearCoatNormalCustomOutput.generated.h" + + + +UCLASS() +class UMaterialExpressionClearCoatNormalCustomOutput : public UMaterialExpressionCustomOutput +{ + GENERATED_UCLASS_BODY() + + UPROPERTY(meta = (RequiredInput = "true")) + FExpressionInput Input; + +#if WITH_EDITOR + virtual int32 Compile(class FMaterialCompiler* Compiler, int32 OutputIndex, int32 MultiplexIndex) override; + virtual void GetCaption(TArray& OutCaptions) const override; +#endif + + virtual FExpressionInput* GetInput(int32 InputIndex) override; + + + // Begin UObject Interface +#if WITH_EDITOR + + virtual uint32 GetInputType(int32 InputIndex) override { return MCT_Float3; } +#endif + + + virtual FString GetFunctionName() const override { return TEXT("ClearCoatBottomNormal"); } + +}; + + + diff --git a/Engine/Source/Runtime/Engine/Private/Actor.cpp b/Engine/Source/Runtime/Engine/Private/Actor.cpp index d13a7a38885b..f0c3b2bece91 100644 --- a/Engine/Source/Runtime/Engine/Private/Actor.cpp +++ b/Engine/Source/Runtime/Engine/Private/Actor.cpp @@ -496,6 +496,26 @@ void AActor::Serialize(FArchive& Ar) } } } + + // When duplicating for PIE all components need to be gathered up and duplicated even if there are no other property references to them + // otherwise we can end up with Attach Parents that do not get redirected to the correct component. However, if there is a transient component + // we'll let that drop + if (Ar.GetPortFlags() & PPF_DuplicateForPIE) + { + TArray DuplicatingComponents; + if (Ar.IsSaving()) + { + DuplicatingComponents.Reserve(OwnedComponents.Num()); + for (UActorComponent* OwnedComponent : OwnedComponents) + { + if (!OwnedComponent->HasAnyFlags(RF_Transient)) + { + DuplicatingComponents.Add(OwnedComponent); + } + } + } + Ar << DuplicatingComponents; + } #endif Super::Serialize(Ar); diff --git a/Engine/Source/Runtime/Engine/Private/ActorConstruction.cpp b/Engine/Source/Runtime/Engine/Private/ActorConstruction.cpp index 4ad52960023b..bae375397d0f 100644 --- a/Engine/Source/Runtime/Engine/Private/ActorConstruction.cpp +++ b/Engine/Source/Runtime/Engine/Private/ActorConstruction.cpp @@ -459,18 +459,11 @@ void AActor::RerunConstructionScripts() } } -void AActor::FixComponentsFromDynamicClass() -{ - -} - void AActor::ExecuteConstruction(const FTransform& Transform, const FComponentInstanceDataCache* InstanceDataCache, bool bIsDefaultTransform) { check(!IsPendingKill()); check(!HasAnyFlags(RF_BeginDestroyed|RF_FinishDestroyed)); - FixComponentsFromDynamicClass(); - // ensure that any existing native root component gets this new transform // we can skip this in the default case as the given transform will be the root component's transform if (RootComponent && !bIsDefaultTransform) diff --git a/Engine/Source/Runtime/Engine/Private/Animation/AnimComposite.cpp b/Engine/Source/Runtime/Engine/Private/Animation/AnimComposite.cpp index 43c67a9e3418..1086fa46b966 100644 --- a/Engine/Source/Runtime/Engine/Private/Animation/AnimComposite.cpp +++ b/Engine/Source/Runtime/Engine/Private/Animation/AnimComposite.cpp @@ -28,46 +28,47 @@ void UAnimComposite::ReplaceReferredAnimations(const TMap& OutActiveNotifies) const +{ + const bool bMovingForward = (RateScale >= 0.f); + + Super::GetAnimNotifiesFromDeltaPositions(PreviousPosition, CurrentPosition, OutActiveNotifies); + + if (bMovingForward) + { + if (PreviousPosition <= CurrentPosition) + { + AnimationTrack.GetAnimNotifiesFromTrackPositions(PreviousPosition, CurrentPosition, OutActiveNotifies); + } + else + { + AnimationTrack.GetAnimNotifiesFromTrackPositions(PreviousPosition, SequenceLength, OutActiveNotifies); + AnimationTrack.GetAnimNotifiesFromTrackPositions(0.f, CurrentPosition, OutActiveNotifies); + } + } + else + { + if (PreviousPosition >= CurrentPosition) + { + AnimationTrack.GetAnimNotifiesFromTrackPositions(PreviousPosition, CurrentPosition, OutActiveNotifies); + } + else + { + AnimationTrack.GetAnimNotifiesFromTrackPositions(PreviousPosition, 0.f, OutActiveNotifies); + AnimationTrack.GetAnimNotifiesFromTrackPositions(SequenceLength, CurrentPosition, OutActiveNotifies); + } + } +} + void UAnimComposite::HandleAssetPlayerTickedInternal(FAnimAssetTickContext &Context, const float PreviousTime, const float MoveDelta, const FAnimTickRecord &Instance, struct FAnimNotifyQueue& NotifyQueue) const { Super::HandleAssetPlayerTickedInternal(Context, PreviousTime, MoveDelta, Instance, NotifyQueue); - // if should generate notifies - if (Context.ShouldGenerateNotifies()) - { - // make sure to check animation track notifies - TArray AnimNotifies; - const bool bMovingForward = (RateScale >= 0.f); - - if (bMovingForward) - { - const float CurrentTime = *Instance.TimeAccumulator; - if (PreviousTime <= CurrentTime) - { - AnimationTrack.GetAnimNotifiesFromTrackPositions(PreviousTime, CurrentTime, AnimNotifies); - } - else - { - AnimationTrack.GetAnimNotifiesFromTrackPositions(PreviousTime, SequenceLength, AnimNotifies); - AnimationTrack.GetAnimNotifiesFromTrackPositions(0.f, CurrentTime, AnimNotifies); - } - } - else - { - const float CurrentTime = *Instance.TimeAccumulator; - if (PreviousTime >= CurrentTime) - { - AnimationTrack.GetAnimNotifiesFromTrackPositions(PreviousTime, CurrentTime, AnimNotifies); - } - else - { - AnimationTrack.GetAnimNotifiesFromTrackPositions(PreviousTime, 0.f, AnimNotifies); - AnimationTrack.GetAnimNotifiesFromTrackPositions(SequenceLength, CurrentTime, AnimNotifies); - } - } - - NotifyQueue.AddAnimNotifies(AnimNotifies, Instance.EffectiveBlendWeight); - } ExtractRootMotionFromTrack(AnimationTrack, PreviousTime, PreviousTime + MoveDelta, Context.RootMotionMovementParams); } diff --git a/Engine/Source/Runtime/Engine/Private/Animation/AnimCompositeBase.cpp b/Engine/Source/Runtime/Engine/Private/Animation/AnimCompositeBase.cpp index 01754baef1ba..0accb7e87659 100644 --- a/Engine/Source/Runtime/Engine/Private/Animation/AnimCompositeBase.cpp +++ b/Engine/Source/Runtime/Engine/Private/Animation/AnimCompositeBase.cpp @@ -630,6 +630,10 @@ void FAnimTrack::InvalidateRecursiveAsset(class UAnimCompositeBase* CheckAsset) AnimSegment.bValid = IsValidToAdd(CompositeBase); } } + else + { + AnimSegment.bValid = IsValidToAdd(AnimSegment.AnimReference); + } } } @@ -665,6 +669,19 @@ void FAnimTrack::GetAnimNotifiesFromTrackPositions(const float& PreviousTrackPos } } +bool FAnimTrack::IsNotifyAvailable() const +{ + for (int32 SegmentIndex = 0; SegmentIndex < AnimSegments.Num(); ++SegmentIndex) + { + if (AnimSegments[SegmentIndex].IsNotifyAvailable()) + { + return true; + } + } + + return false; +} + bool FAnimTrack::IsValidToAdd(const UAnimSequenceBase* SequenceBase) const { bool bValid = false; diff --git a/Engine/Source/Runtime/Engine/Private/Animation/AnimInstance.cpp b/Engine/Source/Runtime/Engine/Private/Animation/AnimInstance.cpp index 6f1a501b6751..f069cac268dd 100644 --- a/Engine/Source/Runtime/Engine/Private/Animation/AnimInstance.cpp +++ b/Engine/Source/Runtime/Engine/Private/Animation/AnimInstance.cpp @@ -389,22 +389,12 @@ PRAGMA_ENABLE_DEPRECATION_WARNINGS // so that node knows where montage is UpdateMontage(DeltaSeconds); - if(NeedsImmediateUpdate(DeltaSeconds)) + if(bNeedsValidRootMotion || NeedsImmediateUpdate(DeltaSeconds)) { // cant use parallel update, so just do the work here Proxy.UpdateAnimation(); PostUpdateAnimation(); } - else if(bNeedsValidRootMotion && RootMotionMode == ERootMotionMode::RootMotionFromMontagesOnly) - { - // We may have just partially blended root motion, so make it up to 1 by - // blending in identity too - FRootMotionMovementParams& ExtractedRootMotion = Proxy.GetExtractedRootMotion(); - if (ExtractedRootMotion.bHasRootMotion) - { - ExtractedRootMotion.MakeUpToFullWeight(); - } - } } void UAnimInstance::PreUpdateAnimation(float DeltaSeconds) @@ -495,7 +485,6 @@ bool UAnimInstance::NeedsImmediateUpdate(float DeltaSeconds) const bEvaluationPhaseSkipped || CVarUseParallelAnimUpdate.GetValueOnGameThread() == 0 || CVarUseParallelAnimationEvaluation.GetValueOnGameThread() == 0 || - GetWorld()->IsServer() || !bUseParallelUpdateAnimation || DeltaSeconds == 0.0f || RootMotionMode == ERootMotionMode::RootMotionFromEverything; @@ -506,6 +495,11 @@ bool UAnimInstance::NeedsUpdate() const return bNeedsUpdate; } +void UAnimInstance::PreEvaluateAnimation() +{ + GetProxyOnGameThread().PreEvaluateAnimation(this); +} + void UAnimInstance::EvaluateAnimation(FPoseContext& Output) { GetProxyOnGameThread().EvaluateAnimation(Output); @@ -563,6 +557,8 @@ void UAnimInstance::PostEvaluateAnimation() SCOPE_CYCLE_COUNTER(STAT_BlueprintPostEvaluateAnimation); BlueprintPostEvaluateAnimation(); } + + GetProxyOnGameThread().ClearObjects(); } void UAnimInstance::NativeInitializeAnimation() diff --git a/Engine/Source/Runtime/Engine/Private/Animation/AnimInstanceProxy.cpp b/Engine/Source/Runtime/Engine/Private/Animation/AnimInstanceProxy.cpp index 9f9963563c10..39e66dda09d7 100644 --- a/Engine/Source/Runtime/Engine/Private/Animation/AnimInstanceProxy.cpp +++ b/Engine/Source/Runtime/Engine/Private/Animation/AnimInstanceProxy.cpp @@ -41,15 +41,7 @@ void FAnimInstanceProxy::Initialize(UAnimInstance* InAnimInstance) AnimClassInterface = IAnimClassInterface::GetFromClass(InAnimInstance->GetClass()); - USkeletalMeshComponent* OwnerComponent = InAnimInstance->GetSkelMeshComponent(); - if (OwnerComponent->SkeletalMesh != NULL) - { - Skeleton = OwnerComponent->SkeletalMesh->Skeleton; - } - else - { - Skeleton = nullptr; - } + InitializeObjects(InAnimInstance); if (AnimClassInterface) { @@ -98,8 +90,6 @@ void FAnimInstanceProxy::Initialize(UAnimInstance* InAnimInstance) #endif } - SkeletalMeshComponent = InAnimInstance->GetSkelMeshComponent(); - #if !NO_LOGGING ActorName = GetNameSafe(InAnimInstance->GetOwningActor()); #endif @@ -169,6 +159,8 @@ void FAnimInstanceProxy::PreUpdate(UAnimInstance* InAnimInstance, float DeltaSec RootMotionMode = InAnimInstance->RootMotionMode; bShouldExtractRootMotion = InAnimInstance->ShouldExtractRootMotion(); + InitializeObjects(InAnimInstance); + // Save off LOD level that we're currently using. LODLevel = InAnimInstance->GetSkelMeshComponent()->PredictedLODLevel; @@ -214,6 +206,25 @@ void FAnimInstanceProxy::PostUpdate(UAnimInstance* InAnimInstance) const InAnimInstance->NotifyQueue.ApplyMontageNotifies(*this); } +void FAnimInstanceProxy::InitializeObjects(UAnimInstance* InAnimInstance) +{ + SkeletalMeshComponent = InAnimInstance->GetSkelMeshComponent(); + if (SkeletalMeshComponent->SkeletalMesh != nullptr) + { + Skeleton = SkeletalMeshComponent->SkeletalMesh->Skeleton; + } + else + { + Skeleton = nullptr; + } +} + +void FAnimInstanceProxy::ClearObjects() +{ + SkeletalMeshComponent = nullptr; + Skeleton = nullptr; +} + FAnimTickRecord& FAnimInstanceProxy::CreateUninitializedTickRecord(int32 GroupIndex, FAnimGroupInstance*& OutSyncGroupPtr) { // Find or create the sync group if there is one @@ -661,6 +672,11 @@ void FAnimInstanceProxy::UpdateAnimation() TickAssetPlayerInstances(CurrentDeltaSeconds); } +void FAnimInstanceProxy::PreEvaluateAnimation(UAnimInstance* InAnimInstance) +{ + InitializeObjects(InAnimInstance); +} + void FAnimInstanceProxy::EvaluateAnimation(FPoseContext& Output) { ANIM_MT_SCOPE_CYCLE_COUNTER(EvaluateAnimInstance, !IsInGameThread()); diff --git a/Engine/Source/Runtime/Engine/Private/Animation/AnimSequenceBase.cpp b/Engine/Source/Runtime/Engine/Private/Animation/AnimSequenceBase.cpp index 340db5713f17..d8887fdbef0b 100644 --- a/Engine/Source/Runtime/Engine/Private/Animation/AnimSequenceBase.cpp +++ b/Engine/Source/Runtime/Engine/Private/Animation/AnimSequenceBase.cpp @@ -113,6 +113,10 @@ void UAnimSequenceBase::SortNotifies() Notifies.Sort(); } +bool UAnimSequenceBase::IsNotifyAvailable() const +{ + return (Notifies.Num() != 0) && (SequenceLength > 0.f); +} /** * Retrieves AnimNotifies given a StartTime and a DeltaTime. * Time will be advanced and support looping if bAllowLooping is true. @@ -121,12 +125,17 @@ void UAnimSequenceBase::SortNotifies() */ void UAnimSequenceBase::GetAnimNotifies(const float& StartTime, const float& DeltaTime, const bool bAllowLooping, TArray & OutActiveNotifies) const { - // Early out if we have no notifies - if( (Notifies.Num() == 0) || (DeltaTime == 0.f) || (SequenceLength==0.f)) + if(DeltaTime == 0.f) { return; } + // Early out if we have no notifies + if (!IsNotifyAvailable()) + { + return; + } + bool const bPlayingBackwards = (DeltaTime < 0.f); float PreviousPosition = StartTime; float CurrentPosition = StartTime; diff --git a/Engine/Source/Runtime/Engine/Private/Animation/AnimSingleNodeInstance.cpp b/Engine/Source/Runtime/Engine/Private/Animation/AnimSingleNodeInstance.cpp index f579444a8286..b82482bdfba6 100644 --- a/Engine/Source/Runtime/Engine/Private/Animation/AnimSingleNodeInstance.cpp +++ b/Engine/Source/Runtime/Engine/Private/Animation/AnimSingleNodeInstance.cpp @@ -29,7 +29,41 @@ UAnimSingleNodeInstance::UAnimSingleNodeInstance(const FObjectInitializer& Objec void UAnimSingleNodeInstance::SetAnimationAsset(class UAnimationAsset* NewAsset, bool bInIsLooping, float InPlayRate) { + if (NewAsset != CurrentAsset) + { + CurrentAsset = NewAsset; + } + FAnimSingleNodeInstanceProxy& Proxy = GetProxyOnGameThread(); + + if ( +#if WITH_EDITOR + !Proxy.CanProcessAdditiveAnimations() && +#endif + NewAsset && NewAsset->IsValidAdditive()) + { + UE_LOG(LogAnimation, Warning, TEXT("Setting an additive animation (%s) on an AnimSingleNodeInstance is not allowed. This will not function correctly in cooked builds!"), *NewAsset->GetName()); + } + + USkeletalMeshComponent* MeshComponent = GetSkelMeshComponent(); + if (MeshComponent) + { + if (MeshComponent->SkeletalMesh == nullptr) + { + // if it does not have SkeletalMesh, we nullify it + CurrentAsset = nullptr; + } + else if (CurrentAsset != nullptr) + { + // if we have an asset, make sure their skeleton matches, otherwise, null it + if (MeshComponent->SkeletalMesh == nullptr || MeshComponent->SkeletalMesh->Skeleton != CurrentAsset->GetSkeleton()) + { + // clear asset since we do not have matching skeleton + CurrentAsset = nullptr; + } + } + } + Proxy.SetAnimationAsset(NewAsset, GetSkelMeshComponent(), bInIsLooping, InPlayRate); // if composite, we want to make sure this is valid @@ -58,9 +92,32 @@ void UAnimSingleNodeInstance::SetAnimationAsset(class UAnimationAsset* NewAsset, } } -void UAnimSingleNodeInstance::SetVertexAnimation(UVertexAnimation * NewVertexAnim, bool bIsLooping, float InPlayRate) +void UAnimSingleNodeInstance::SetVertexAnimation(UVertexAnimation* NewVertexAnim, bool bIsLooping, float InPlayRate) { - GetProxyOnGameThread().SetVertexAnimation(NewVertexAnim, bIsLooping, InPlayRate); + if (NewVertexAnim != CurrentVertexAnim) + { + CurrentVertexAnim = NewVertexAnim; + } + + if (USkeletalMeshComponent * MeshComponent = GetSkelMeshComponent()) + { + if (MeshComponent->SkeletalMesh == nullptr) + { + // if it does not have SkeletalMesh, we nullify it + CurrentVertexAnim = NULL; + } + else if (CurrentVertexAnim != nullptr) + { + // if we have an anim, make sure their mesh matches, otherwise, null it + if (MeshComponent->SkeletalMesh != CurrentVertexAnim->BaseSkelMesh) + { + // clear asset since we do not have matching skeleton + CurrentVertexAnim = nullptr; + } + } + } + + GetProxyOnGameThread().SetVertexAnimation(CurrentVertexAnim, bIsLooping, InPlayRate); // reinitialize InitializeAnimation(); @@ -131,10 +188,10 @@ void UAnimSingleNodeInstance::UpdateBlendspaceSamples(FVector InBlendInput) void UAnimSingleNodeInstance::RestartMontage(UAnimMontage* Montage, FName FromSection) { - FAnimSingleNodeInstanceProxy& Proxy = GetProxyOnGameThread(); - - if( Montage == Proxy.GetCurrentAsset() ) + if(Montage == CurrentAsset) { + FAnimSingleNodeInstanceProxy& Proxy = GetProxyOnGameThread(); + Proxy.ResetWeightInfo(); Montage_Play(Montage, Proxy.GetPlayRate()); if( FromSection != NAME_None ) @@ -161,7 +218,7 @@ void UAnimSingleNodeInstance::NativePostEvaluateAnimation() void UAnimSingleNodeInstance::OnMontageInstanceStopped(FAnimMontageInstance& StoppedMontageInstance) { FAnimSingleNodeInstanceProxy& Proxy = GetProxyOnGameThread(); - if (StoppedMontageInstance.Montage == Proxy.GetCurrentAsset()) + if (StoppedMontageInstance.Montage == CurrentAsset) { Proxy.SetCurrentTime(StoppedMontageInstance.GetPosition()); } @@ -199,7 +256,7 @@ void UAnimSingleNodeInstance::SetLooping(bool bIsLooping) FAnimSingleNodeInstanceProxy& Proxy = GetProxyOnGameThread(); Proxy.SetLooping(bIsLooping); - if (UAnimMontage* Montage = Cast(GetCurrentAsset())) + if (UAnimMontage* Montage = Cast(CurrentAsset)) { SetMontageLoop(Montage, Proxy.IsLooping(), Montage_GetCurrentSection()); } @@ -216,7 +273,7 @@ void UAnimSingleNodeInstance::SetPlaying(bool bIsPlaying) } else if (Proxy.IsPlaying()) { - UAnimMontage* Montage = Cast(GetCurrentAsset()); + UAnimMontage* Montage = Cast(CurrentAsset); if (Montage) { RestartMontage(Montage); @@ -262,12 +319,12 @@ void UAnimSingleNodeInstance::SetPlayRate(float InPlayRate) UAnimationAsset* UAnimSingleNodeInstance::GetCurrentAsset() { - return GetProxyOnGameThread().GetCurrentAsset(); + return CurrentAsset; } UVertexAnimation* UAnimSingleNodeInstance::GetCurrentVertexAnimation() { - return GetProxyOnGameThread().GetCurrentVertexAnimation(); + return CurrentVertexAnim; } float UAnimSingleNodeInstance::GetCurrentTime() const @@ -296,7 +353,7 @@ void UAnimSingleNodeInstance::SetPositionWithPreviousTime(float InPosition, floa // this will need to handle manually, emptying, it and collect it, and trigger them at once. if (bFireNotifies) { - UAnimSequenceBase * SequenceBase = Cast (Proxy.GetCurrentAsset()); + UAnimSequenceBase * SequenceBase = Cast (CurrentAsset); if (SequenceBase) { NotifyQueue.Reset(GetSkelMeshComponent()); @@ -331,12 +388,24 @@ void UAnimSingleNodeInstance::SetBlendSpaceInput(const FVector& InBlendInput) float UAnimSingleNodeInstance::GetLength() { - return GetProxyOnGameThread().GetLength(); + if ((CurrentAsset != NULL)) + { + if (UBlendSpace* BlendSpace = Cast(CurrentAsset)) + { + return BlendSpace->AnimLength; + } + else if (UAnimSequenceBase* SequenceBase = Cast(CurrentAsset)) + { + return SequenceBase->SequenceLength; + } + } + + return 0.f; } void UAnimSingleNodeInstance::StepForward() { - if (UAnimSequence* Sequence = Cast(GetCurrentAsset())) + if (UAnimSequence* Sequence = Cast(CurrentAsset)) { FAnimSingleNodeInstanceProxy& Proxy = GetProxyOnGameThread(); @@ -349,7 +418,7 @@ void UAnimSingleNodeInstance::StepForward() void UAnimSingleNodeInstance::StepBackward() { - if (UAnimSequence* Sequence = Cast(GetCurrentAsset())) + if (UAnimSequence* Sequence = Cast(CurrentAsset)) { FAnimSingleNodeInstanceProxy& Proxy = GetProxyOnGameThread(); @@ -367,7 +436,7 @@ FAnimInstanceProxy* UAnimSingleNodeInstance::CreateAnimInstanceProxy() FVector UAnimSingleNodeInstance::GetFilterLastOutput() { - if (UBlendSpaceBase* Blendspace = Cast(GetCurrentAsset())) + if (UBlendSpaceBase* Blendspace = Cast(CurrentAsset)) { FAnimSingleNodeInstanceProxy& Proxy = GetProxyOnGameThread(); return Proxy.GetFilterLastOutput(); diff --git a/Engine/Source/Runtime/Engine/Private/Animation/AnimSingleNodeInstanceProxy.cpp b/Engine/Source/Runtime/Engine/Private/Animation/AnimSingleNodeInstanceProxy.cpp index 7c23bbfc5d5a..28efe53b4422 100644 --- a/Engine/Source/Runtime/Engine/Private/Animation/AnimSingleNodeInstanceProxy.cpp +++ b/Engine/Source/Runtime/Engine/Private/Animation/AnimSingleNodeInstanceProxy.cpp @@ -6,6 +6,7 @@ #include "Animation/AnimMontage.h" #include "Animation/VertexAnim/VertexAnimation.h" #include "Animation/BlendSpace.h" +#include "Animation/AnimSingleNodeInstance.h" void FAnimSingleNodeInstanceProxy::Initialize(UAnimInstance* InAnimInstance) { @@ -259,6 +260,23 @@ void FAnimSingleNodeInstanceProxy::PostUpdate(UAnimInstance* InAnimInstance) con } } +void FAnimSingleNodeInstanceProxy::InitializeObjects(UAnimInstance* InAnimInstance) +{ + FAnimInstanceProxy::InitializeObjects(InAnimInstance); + + UAnimSingleNodeInstance* AnimSingleNodeInstance = CastChecked(InAnimInstance); + CurrentAsset = AnimSingleNodeInstance->CurrentAsset; + CurrentVertexAnim = AnimSingleNodeInstance->CurrentVertexAnim; +} + +void FAnimSingleNodeInstanceProxy::ClearObjects() +{ + FAnimInstanceProxy::ClearObjects(); + + CurrentAsset = nullptr; + CurrentVertexAnim = nullptr; +} + void FAnimSingleNodeInstanceProxy::InternalBlendSpaceEvaluatePose(class UBlendSpaceBase* BlendSpace, TArray& BlendSampleDataCache, FPoseContext& OutContext) { if (BlendSpace->IsValidAdditive()) @@ -296,38 +314,6 @@ void FAnimSingleNodeInstanceProxy::InternalBlendSpaceEvaluatePose(class UBlendSp void FAnimSingleNodeInstanceProxy::SetAnimationAsset(class UAnimationAsset* NewAsset, USkeletalMeshComponent* MeshComponent, bool bIsLooping, float InPlayRate) { - if (NewAsset != CurrentAsset) - { - CurrentAsset = NewAsset; - } - - if ( -#if WITH_EDITOR - !bCanProcessAdditiveAnimations && -#endif - NewAsset && NewAsset->IsValidAdditive()) - { - UE_LOG(LogAnimation, Warning, TEXT("Setting an additve animation (%s) on an AnimSingleNodeInstance is not allowed. This will not function correctly in cooked builds!"), *NewAsset->GetName()); - } - - if (MeshComponent) - { - if (MeshComponent->SkeletalMesh == NULL) - { - // if it does not have SkeletalMesh, we nullify it - CurrentAsset = NULL; - } - else if (CurrentAsset != NULL) - { - // if we have an asset, make sure their skeleton matches, otherwise, null it - if (GetSkeleton() != CurrentAsset->GetSkeleton()) - { - // clear asset since we do not have matching skeleton - CurrentAsset = NULL; - } - } - } - bLooping = bIsLooping; PlayRate = InPlayRate; CurrentTime = 0.f; @@ -359,29 +345,6 @@ void FAnimSingleNodeInstanceProxy::UpdateBlendspaceSamples(FVector InBlendInput) void FAnimSingleNodeInstanceProxy::SetVertexAnimation(UVertexAnimation * NewVertexAnim, bool bIsLooping, float InPlayRate) { - if (NewVertexAnim != CurrentVertexAnim) - { - CurrentVertexAnim = NewVertexAnim; - } - - if (USkeletalMeshComponent * MeshComponent = GetSkelMeshComponent()) - { - if (MeshComponent->SkeletalMesh == NULL) - { - // if it does not have SkeletalMesh, we nullify it - CurrentVertexAnim = NULL; - } - else if (CurrentVertexAnim != NULL) - { - // if we have an anim, make sure their mesh matches, otherwise, null it - if (MeshComponent->SkeletalMesh != CurrentVertexAnim->BaseSkelMesh) - { - // clear asset since we do not have matching skeleton - CurrentVertexAnim = NULL; - } - } - } - bLooping = bIsLooping; PlayRate = InPlayRate; } @@ -414,23 +377,6 @@ void FAnimSingleNodeInstanceProxy::SetReverse(bool bInReverse) }*/ } -float FAnimSingleNodeInstanceProxy::GetLength() -{ - if ((CurrentAsset != NULL)) - { - if (UBlendSpace* BlendSpace = Cast(CurrentAsset)) - { - return BlendSpace->AnimLength; - } - else if (UAnimSequenceBase* SequenceBase = Cast(CurrentAsset)) - { - return SequenceBase->SequenceLength; - } - } - - return 0.f; -} - void FAnimSingleNodeInstanceProxy::SetBlendSpaceInput(const FVector& InBlendInput) { BlendSpaceInput = InBlendInput; diff --git a/Engine/Source/Runtime/Engine/Private/BlueprintGeneratedClass.cpp b/Engine/Source/Runtime/Engine/Private/BlueprintGeneratedClass.cpp index 6e541db30f33..5b11b8f7cc9a 100644 --- a/Engine/Source/Runtime/Engine/Private/BlueprintGeneratedClass.cpp +++ b/Engine/Source/Runtime/Engine/Private/BlueprintGeneratedClass.cpp @@ -363,19 +363,20 @@ void UBlueprintGeneratedClass::BuildCustomPropertyListForPostConstruction(FCusto } } -void UBlueprintGeneratedClass::BuildCustomArrayPropertyListForPostConstruction(UArrayProperty* ArrayProperty, FCustomPropertyListNode*& InPropertyList, const uint8* DataPtr, const uint8* DefaultDataPtr) +void UBlueprintGeneratedClass::BuildCustomArrayPropertyListForPostConstruction(UArrayProperty* ArrayProperty, FCustomPropertyListNode*& InPropertyList, const uint8* DataPtr, const uint8* DefaultDataPtr, int32 StartIndex) { FCustomPropertyListNode** CurrentArrayNodePtr = &InPropertyList; FScriptArrayHelper ArrayValueHelper(ArrayProperty, DataPtr); FScriptArrayHelper DefaultArrayValueHelper(ArrayProperty, DefaultDataPtr); - for (int32 ArrayValueIndex = 0; ArrayValueIndex < ArrayValueHelper.Num(); ++ArrayValueIndex) + for (int32 ArrayValueIndex = StartIndex; ArrayValueIndex < ArrayValueHelper.Num(); ++ArrayValueIndex) { - if (ArrayValueIndex < DefaultArrayValueHelper.Num()) + const int32 DefaultArrayValueIndex = ArrayValueIndex - StartIndex; + if (DefaultArrayValueIndex < DefaultArrayValueHelper.Num()) { const uint8* ArrayPropertyValue = ArrayValueHelper.GetRawPtr(ArrayValueIndex); - const uint8* DefaultArrayPropertyValue = DefaultArrayValueHelper.GetRawPtr(ArrayValueIndex); + const uint8* DefaultArrayPropertyValue = DefaultArrayValueHelper.GetRawPtr(DefaultArrayValueIndex); if (UStructProperty* InnerStructProperty = Cast(ArrayProperty->Inner)) { @@ -434,8 +435,25 @@ void UBlueprintGeneratedClass::BuildCustomArrayPropertyListForPostConstruction(U } else { - // Signals the "end" of differences with the default value (signals that remaining values should be copied in full) - *CurrentArrayNodePtr = new(CustomPropertyListForPostConstruction) FCustomPropertyListNode(nullptr, ArrayValueIndex); + // Create a temp default array as a placeholder to compare against the remaining elements in the value. + FScriptArray TempDefaultArray; + const int32 Count = ArrayValueHelper.Num() - DefaultArrayValueHelper.Num(); + TempDefaultArray.Add(Count, ArrayProperty->Inner->ElementSize); + uint8 *Dest = (uint8*)TempDefaultArray.GetData(); + if (ArrayProperty->Inner->PropertyFlags & CPF_ZeroConstructor) + { + FMemory::Memzero(Dest, Count * ArrayProperty->Inner->ElementSize); + } + else + { + for (int32 i = 0; i < Count; i++, Dest += ArrayProperty->Inner->ElementSize) + { + ArrayProperty->Inner->InitializeValue(Dest); + } + } + + // Recursively fill out the property list for the remainder of the elements in the value that extend beyond the size of the default value. + BuildCustomArrayPropertyListForPostConstruction(ArrayProperty, *CurrentArrayNodePtr, DataPtr, (uint8*)&TempDefaultArray, ArrayValueIndex); // Don't need to record anything else. break; diff --git a/Engine/Source/Runtime/Engine/Private/Components/AudioComponent.cpp b/Engine/Source/Runtime/Engine/Private/Components/AudioComponent.cpp index 1ed016d3b20b..44d07ec7021c 100644 --- a/Engine/Source/Runtime/Engine/Private/Components/AudioComponent.cpp +++ b/Engine/Source/Runtime/Engine/Private/Components/AudioComponent.cpp @@ -362,7 +362,7 @@ void UAudioComponent::PlaybackCompleted(bool bFailedToStart) } // Auto destruction is handled via marking object for deletion. - if (bAutoDestroy) + if (bAutoDestroy && !bIsActive) { DestroyComponent(); } diff --git a/Engine/Source/Runtime/Engine/Private/Components/ChildActorComponent.cpp b/Engine/Source/Runtime/Engine/Private/Components/ChildActorComponent.cpp index 032a3dffde28..f1e4eac0d1fc 100644 --- a/Engine/Source/Runtime/Engine/Private/Components/ChildActorComponent.cpp +++ b/Engine/Source/Runtime/Engine/Private/Components/ChildActorComponent.cpp @@ -2,6 +2,7 @@ #include "EnginePrivate.h" #include "Components/ChildActorComponent.h" +#include "Net/UnrealNetwork.h" DEFINE_LOG_CATEGORY_STATIC(LogChildActorComponent, Warning, All); @@ -34,6 +35,9 @@ void UChildActorComponent::OnRegister() // so moving Attach to happen in Register ChildRoot->AttachToComponent(this, FAttachmentTransformRules::SnapToTargetNotIncludingScale); } + + // Ensure the components replication is correctly initialized + SetIsReplicated(ChildActor->GetIsReplicated()); } } else if (ChildActorClass) @@ -83,6 +87,29 @@ void UChildActorComponent::PostEditUndo() } #endif +void UChildActorComponent::GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const +{ + Super::GetLifetimeReplicatedProps(OutLifetimeProps); + + DOREPLIFETIME(UChildActorComponent, ChildActor); +} + +void UChildActorComponent::PostRepNotifies() +{ + Super::PostRepNotifies(); + + if (ChildActor) + { + ChildActorClass = ChildActor->GetClass(); + ChildActorName = ChildActor->GetFName(); + } + else + { + ChildActorClass = nullptr; + ChildActorName = NAME_None; + } +} + void UChildActorComponent::OnComponentCreated() { Super::OnComponentCreated(); @@ -94,16 +121,14 @@ void UChildActorComponent::OnComponentDestroyed(bool bDestroyingHierarchy) { Super::OnComponentDestroyed(bDestroyingHierarchy); - const UWorld* const MyWorld = GetWorld(); - DestroyChildActor(MyWorld && !MyWorld->IsGameWorld()); + DestroyChildActor(); } void UChildActorComponent::OnUnregister() { Super::OnUnregister(); - const UWorld* const MyWorld = GetWorld(); - DestroyChildActor(MyWorld && !MyWorld->IsGameWorld()); + DestroyChildActor(); } FChildActorComponentInstanceData::FChildActorComponentInstanceData(const UChildActorComponent* Component) @@ -262,6 +287,18 @@ void UChildActorComponent::PostLoad() void UChildActorComponent::CreateChildActor() { + AActor* MyOwner = GetOwner(); + + if (MyOwner && !MyOwner->HasAuthority()) + { + AActor* ChildClassCDO = (ChildActorClass ? ChildActorClass->GetDefaultObject() : nullptr); + if (ChildClassCDO && ChildClassCDO->GetIsReplicated()) + { + // If we belong to an actor that is not authoritative and the child class is replicated then we expect that Actor will be replicated across so don't spawn one + return; + } + } + // Kill spawned actor if we have one DestroyChildActor(); @@ -273,7 +310,6 @@ void UChildActorComponent::CreateChildActor() { // Before we spawn let's try and prevent cyclic disaster bool bSpawn = true; - AActor* MyOwner = GetOwner(); AActor* Actor = MyOwner; while (Actor && bSpawn) { @@ -323,6 +359,8 @@ void UChildActorComponent::CreateChildActor() ChildActor->FinishSpawning(ComponentToWorld, false, ComponentInstanceData); ChildActor->AttachToComponent(this, FAttachmentTransformRules::SnapToTargetNotIncludingScale); + + SetIsReplicated(ChildActor->GetIsReplicated()); } } } @@ -336,50 +374,62 @@ void UChildActorComponent::CreateChildActor() } } -void UChildActorComponent::DestroyChildActor(const bool bRequiresRename) +void UChildActorComponent::DestroyChildActor() { - // If we own an Actor, kill it now - if (ChildActor != nullptr && !GExitPurge) + // If we own an Actor, kill it now unless we don't have authority on it, for that we rely on the server + if (ChildActor && ChildActor->HasAuthority()) { - // if still alive, destroy, otherwise just clear the pointer - if (!ChildActor->IsPendingKillOrUnreachable()) + if (!GExitPurge) { + // if still alive, destroy, otherwise just clear the pointer + if (!ChildActor->IsPendingKillOrUnreachable()) + { #if WITH_EDITOR - if (CachedInstanceData) - { - delete CachedInstanceData; - CachedInstanceData = nullptr; - } -#else - check(!CachedInstanceData); -#endif - // If we're already tearing down we won't be needing this - if (!HasAnyFlags(RF_BeginDestroyed)) - { - CachedInstanceData = new FChildActorComponentInstanceData(this); - } - - UWorld* World = ChildActor->GetWorld(); - // World may be nullptr during shutdown - if (World != nullptr) - { - UClass* ChildClass = ChildActor->GetClass(); - - // We would like to make certain that our name is not going to accidentally get taken from us while we're destroyed - // so we increment ClassUnique beyond our index to be certain of it. This is ... a bit hacky. - int32& ClassUnique = ChildActor->GetOutermost()->ClassUniqueNameIndexMap.FindOrAdd(ChildClass->GetFName()); - ClassUnique = FMath::Max(ClassUnique, ChildActor->GetFName().GetNumber()); - - if (bRequiresRename) + if (CachedInstanceData) { - const FString ObjectBaseName = FString::Printf(TEXT("DESTROYED_%s_CHILDACTOR"), *ChildClass->GetName()); - const ERenameFlags RenameFlags = ((GetWorld()->IsGameWorld() || IsLoading()) ? REN_DoNotDirty | REN_ForceNoResetLoaders : REN_DoNotDirty); - ChildActor->Rename(*MakeUniqueObjectName(ChildActor->GetOuter(), ChildClass, *ObjectBaseName).ToString(), nullptr, RenameFlags); + delete CachedInstanceData; + CachedInstanceData = nullptr; + } +#else + check(!CachedInstanceData); +#endif + // If we're already tearing down we won't be needing this + if (!HasAnyFlags(RF_BeginDestroyed)) + { + CachedInstanceData = new FChildActorComponentInstanceData(this); + } + + UWorld* World = ChildActor->GetWorld(); + // World may be nullptr during shutdown + if (World != nullptr) + { + UClass* ChildClass = ChildActor->GetClass(); + + // We would like to make certain that our name is not going to accidentally get taken from us while we're destroyed + // so we increment ClassUnique beyond our index to be certain of it. This is ... a bit hacky. + int32& ClassUnique = ChildActor->GetOutermost()->ClassUniqueNameIndexMap.FindOrAdd(ChildClass->GetFName()); + ClassUnique = FMath::Max(ClassUnique, ChildActor->GetFName().GetNumber()); + + // If we are getting here due to garbage collection we can't rename, so we'll have to abandon this child actor name and pick up a new one + if (!IsGarbageCollecting()) + { + const FString ObjectBaseName = FString::Printf(TEXT("DESTROYED_%s_CHILDACTOR"), *ChildClass->GetName()); + const ERenameFlags RenameFlags = ((GetWorld()->IsGameWorld() || IsLoading()) ? REN_DoNotDirty | REN_ForceNoResetLoaders : REN_DoNotDirty); + ChildActor->Rename(*MakeUniqueObjectName(ChildActor->GetOuter(), ChildClass, *ObjectBaseName).ToString(), nullptr, RenameFlags); + } + else + { + ChildActorName = NAME_None; + if (CachedInstanceData) + { + CachedInstanceData->ChildActorName = NAME_None; + } + } + World->DestroyActor(ChildActor); } - World->DestroyActor(ChildActor); } } - } - ChildActor = nullptr; + ChildActor = nullptr; + } } diff --git a/Engine/Source/Runtime/Engine/Private/Components/SkeletalMeshComponent.cpp b/Engine/Source/Runtime/Engine/Private/Components/SkeletalMeshComponent.cpp index 6e005f792938..76ed97b6c66d 100644 --- a/Engine/Source/Runtime/Engine/Private/Components/SkeletalMeshComponent.cpp +++ b/Engine/Source/Runtime/Engine/Private/Components/SkeletalMeshComponent.cpp @@ -332,6 +332,10 @@ void USkeletalMeshComponent::OnRegister() void USkeletalMeshComponent::OnUnregister() { + const bool bBlockOnTask = true; // wait on evaluation task so we complete any work before this component goes away + const bool bPerformPostAnimEvaluation = false; // Skip post evaluation, it would be wasted work + HandleExistingParallelEvaluationTask(bBlockOnTask, bPerformPostAnimEvaluation); + #if WITH_APEX_CLOTHING //clothing actors will be re-created in TickClothing ReleaseAllClothingResources(); @@ -1239,6 +1243,11 @@ void USkeletalMeshComponent::RefreshBoneTransforms(FActorComponentTickFunction* CachedCurve.Empty(); } + if(AnimScriptInstance) + { + AnimScriptInstance->PreEvaluateAnimation(); + } + if (bDoParallelEvaluation) { QUICK_SCOPE_CYCLE_COUNTER(STAT_USkeletalMeshComponent_RefreshBoneTransforms_SetupParallel); @@ -2478,3 +2487,10 @@ void USkeletalMeshComponent::UnregisterOnPhysicsCreatedDelegate(const FDelegateH { OnSkelMeshPhysicsCreated.Remove(DelegateHandle); } + +bool USkeletalMeshComponent::MoveComponentImpl(const FVector& Delta, const FQuat& NewRotation, bool bSweep, FHitResult* OutHit /*= NULL*/, EMoveComponentFlags MoveFlags /*= MOVECOMP_NoFlags*/, ETeleportType Teleport /*= ETeleportType::None*/) +{ + // If we're simulating physics ignore teleport type, we just want to teleport. + ETeleportType NewTeleportType = BodyInstance.bSimulatePhysics ? ETeleportType::TeleportPhysics : Teleport; + return Super::MoveComponentImpl(Delta, NewRotation, bSweep, OutHit, MoveFlags, NewTeleportType); +} diff --git a/Engine/Source/Runtime/Engine/Private/Components/SplineComponent.cpp b/Engine/Source/Runtime/Engine/Private/Components/SplineComponent.cpp index 58134588ce8e..f454f3e31d65 100644 --- a/Engine/Source/Runtime/Engine/Private/Components/SplineComponent.cpp +++ b/Engine/Source/Runtime/Engine/Private/Components/SplineComponent.cpp @@ -17,12 +17,14 @@ USplineComponent::USplineComponent(const FObjectInitializer& ObjectInitializer) , bStationaryEndpoints(false) , bSplineHasBeenEdited(false) , bInputSplinePointsToConstructionScript(false) - , bAlwaysRenderInEditor(true) + , bDrawDebug(true) , bClosedLoop(false) , DefaultUpVector(FVector::UpVector) -#if WITH_EDITORONLY_DATA +#if !UE_BUILD_SHIPPING , EditorUnselectedSplineSegmentColor(FLinearColor(1.0f, 1.0f, 1.0f)) , EditorSelectedSplineSegmentColor(FLinearColor(1.0f, 0.0f, 0.0f)) +#endif +#if WITH_EDITORONLY_DATA , bShouldVisualizeScale(false) , ScaleVisualizationWidth(30.0f) #endif @@ -439,7 +441,7 @@ bool USplineComponent::IsClosedLoop() const void USplineComponent::SetUnselectedSplineSegmentColor(const FLinearColor& Color) { -#if WITH_EDITOR +#if !UE_BUILD_SHIPPING EditorUnselectedSplineSegmentColor = Color; #endif } @@ -447,12 +449,19 @@ void USplineComponent::SetUnselectedSplineSegmentColor(const FLinearColor& Color void USplineComponent::SetSelectedSplineSegmentColor(const FLinearColor& Color) { -#if WITH_EDITOR +#if !UE_BUILD_SHIPPING EditorSelectedSplineSegmentColor = Color; #endif } +void USplineComponent::SetDrawDebug(bool bShow) +{ + bDrawDebug = bShow; + MarkRenderStateDirty(); +} + + void USplineComponent::ClearSplinePoints() { SplineInfo.Points.Reset(); @@ -1115,10 +1124,10 @@ FTransform USplineComponent::FindTransformClosestToWorldLocation(const FVector& return GetTransformAtSplineInputKey(Param, CoordinateSpace, bUseScale); } -#if WITH_EDITOR +#if !UE_BUILD_SHIPPING FPrimitiveSceneProxy* USplineComponent::CreateSceneProxy() { - if (!bAlwaysRenderInEditor) + if (!bDrawDebug) { return Super::CreateSceneProxy(); } @@ -1129,7 +1138,7 @@ FPrimitiveSceneProxy* USplineComponent::CreateSceneProxy() FSplineSceneProxy(const USplineComponent* InComponent) : FPrimitiveSceneProxy(InComponent) - , bAlwaysRenderInEditor(InComponent->bAlwaysRenderInEditor) + , bDrawDebug(InComponent->bDrawDebug) , SplineInfo(InComponent->SplineInfo) , LineColor(InComponent->EditorUnselectedSplineSegmentColor) {} @@ -1218,7 +1227,7 @@ FPrimitiveSceneProxy* USplineComponent::CreateSceneProxy() virtual FPrimitiveViewRelevance GetViewRelevance(const FSceneView* View) const override { FPrimitiveViewRelevance Result; - Result.bDrawRelevance = bAlwaysRenderInEditor && !IsSelected() && IsShown(View) && View->Family->EngineShowFlags.Splines; + Result.bDrawRelevance = bDrawDebug && !IsSelected() && IsShown(View) && View->Family->EngineShowFlags.Splines; Result.bDynamicRelevance = true; Result.bShadowRelevance = IsShadowCast(View); Result.bEditorPrimitiveRelevance = UseEditorCompositing(View); @@ -1229,7 +1238,7 @@ FPrimitiveSceneProxy* USplineComponent::CreateSceneProxy() uint32 GetAllocatedSize(void) const { return FPrimitiveSceneProxy::GetAllocatedSize(); } private: - bool bAlwaysRenderInEditor; + bool bDrawDebug; FInterpCurveVector SplineInfo; FLinearColor LineColor; }; @@ -1240,7 +1249,7 @@ FPrimitiveSceneProxy* USplineComponent::CreateSceneProxy() FBoxSphereBounds USplineComponent::CalcBounds(const FTransform& LocalToWorld) const { - if (!bAlwaysRenderInEditor) + if (!bDrawDebug) { // Do as little as possible if not rendering anything return Super::CalcBounds(LocalToWorld); diff --git a/Engine/Source/Runtime/Engine/Private/DemoNetDriver.cpp b/Engine/Source/Runtime/Engine/Private/DemoNetDriver.cpp index 1ce0e2e237c3..654f138f0b8f 100644 --- a/Engine/Source/Runtime/Engine/Private/DemoNetDriver.cpp +++ b/Engine/Source/Runtime/Engine/Private/DemoNetDriver.cpp @@ -537,43 +537,6 @@ bool UDemoNetDriver::InitConnectInternal( FString& Error ) // Create fake control channel ServerConnection->CreateChannel( CHTYPE_Control, 1 ); - - // Attempt to read metadata if it exists - FArchive* MetadataAr = ReplayStreamer->GetMetadataArchive(); - - FNetworkDemoMetadataHeader MetadataHeader; - - if ( MetadataAr != nullptr ) - { - (*MetadataAr) << MetadataHeader; - - // Check metadata magic value - if ( MetadataHeader.Magic != NETWORK_DEMO_METADATA_MAGIC ) - { - Error = FString( TEXT( "Demo metadata file is corrupt" ) ); - UE_LOG( LogDemo, Error, TEXT( "UDemoNetDriver::InitConnect: %s" ), *Error ); - GameInstance->HandleDemoPlaybackFailure( EDemoPlayFailure::Corrupt, Error ); - return false; - } - - // Check version - if ( MetadataHeader.Version != NETWORK_DEMO_METADATA_VERSION ) - { - Error = FString( TEXT( "Demo metadata file version is incorrect" ) ); - UE_LOG( LogDemo, Error, TEXT( "UDemoNetDriver::InitConnect: %s" ), *Error ); - GameInstance->HandleDemoPlaybackFailure( EDemoPlayFailure::InvalidVersion, Error ); - return false; - } - - DemoTotalFrames = MetadataHeader.NumFrames; - DemoTotalTime = MetadataHeader.TotalTime; - - UE_LOG( LogDemo, Log, TEXT( "Starting demo playback with full demo and metadata. Filename: %s, Frames: %i, Version %i" ), *DemoURL.Map, DemoTotalFrames, DemoHeader.Version ); - } - else - { - UE_LOG( LogDemo, Log, TEXT( "Starting demo playback with streaming demo, metadata file not found. Filename: %s, Version %i" ), *DemoURL.Map, DemoHeader.Version ); - } // Default async world loading to the cvar value... bool bAsyncLoadWorld = CVarDemoAsyncLoadWorld.GetValueOnGameThread() > 0; @@ -627,70 +590,12 @@ bool UDemoNetDriver::InitConnectInternal( FString& Error ) auto NewPendingNetGame = NewObject(); + // Set up the pending net game so that the engine can call LoadMap on the next tick. NewPendingNetGame->DemoNetDriver = this; + NewPendingNetGame->URL = DemoURL; + NewPendingNetGame->bSuccessfullyConnected = true; WorldContext->PendingNetGame = NewPendingNetGame; - - bool bSuccess = GEngine->LoadMap( *WorldContext, LocalDemoURL, NewPendingNetGame, LoadMapError ); - -#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) - if ( CVarDemoForceFailure.GetValueOnGameThread() == 2 ) - { - bSuccess = false; - } -#endif - - if ( !bSuccess ) - { - StopDemo(); - - // If we don't have a world that means we failed loading the new world. - // Since there is no world, we must free the net driver ourselves - // Technically the pending net game should handle it, but things aren't quite setup properly to handle that either - if ( WorldContext->World() == NULL ) - { - GEngine->DestroyNamedNetDriver( WorldContext->PendingNetGame, NetDriverName ); - } - - WorldContext->PendingNetGame = NULL; - - GEngine->BrowseToDefaultMap( *WorldContext ); - - Error = LoadMapError; - UE_LOG( LogDemo, Error, TEXT( "UDemoNetDriver::InitConnect: LoadMap failed: failed: %s" ), *Error ); - GameInstance->HandleDemoPlaybackFailure( EDemoPlayFailure::Generic, FString( TEXT( "LoadMap failed" ) ) ); - return false; - } - - SetWorld( WorldContext->World() ); - WorldContext->World()->DemoNetDriver = this; - WorldContext->PendingNetGame = NULL; - - // Read meta data, if it exists - for ( int32 i = 0; i < MetadataHeader.NumStreamingLevels; ++i ) - { - ULevelStreamingKismet* StreamingLevel = NewObject( GetWorld(), NAME_None, RF_NoFlags, NULL ); - - StreamingLevel->bShouldBeLoaded = true; - StreamingLevel->bShouldBeVisible = true; - StreamingLevel->bShouldBlockOnLoad = false; - StreamingLevel->bInitiallyLoaded = true; - StreamingLevel->bInitiallyVisible = true; - - FString PackageName; - FString PackageNameToLoad; - - ( *MetadataAr ) << PackageName; - ( *MetadataAr ) << PackageNameToLoad; - ( *MetadataAr ) << StreamingLevel->LevelTransform; - - StreamingLevel->PackageNameToLoad = FName( *PackageNameToLoad ); - StreamingLevel->SetWorldAssetByPackageName( FName( *PackageName ) ); - - GetWorld()->StreamingLevels.Add( StreamingLevel ); - - UE_LOG( LogDemo, Log, TEXT( " Loading streamingLevel: %s, %s" ), *PackageName, *PackageNameToLoad ); - } } return true; @@ -1530,9 +1435,20 @@ void UDemoNetDriver::TickDemoRecord( float DeltaSeconds ) Actor->CallPreReplication( this ); - const bool bUpdatedExternalData = ( FindOrCreateRepChangedPropertyTracker( Actor ).Get()->ExternalData.Num() > 0 ); + const bool bDidReplicateActor = DemoReplicateActor( Actor, ClientConnections[0], SpectatorController, false ); - if ( DemoReplicateActor( Actor, ClientConnections[0], SpectatorController, false ) || bUpdatedExternalData ) + TSharedPtr PropertyTracker = FindOrCreateRepChangedPropertyTracker( Actor ); + + if (!bDidReplicateActor) + { + // Clear external data if the actor didn't replicate for some reason + PropertyTracker->ExternalData.Empty(); + PropertyTracker->ExternalDataNumBits = 0; + } + + const bool bUpdatedExternalData = PropertyTracker->ExternalData.Num() > 0; + + if ( bDidReplicateActor || bUpdatedExternalData ) { // Choose an optimal time, we choose 70% of the actual rate to allow frequency to go up if needed ActorInfo->OptimalNetUpdateDelta = FMath::Clamp( LastReplicateDelta * 0.7f, MinOptimalDelta, MaxOptimalDelta ); @@ -2680,6 +2596,81 @@ void UDemoNetDriver::NotifyGotoTimeFinished(bool bWasSuccessful) } } +void UDemoNetDriver::PendingNetGameLoadMapCompleted() +{ + // Attempt to read metadata if it exists + FArchive* const MetadataAr = ReplayStreamer.IsValid() ? ReplayStreamer->GetMetadataArchive() : nullptr; + UGameInstance* const GameInstance = GetWorld()->GetGameInstance(); + + if ( !GameInstance ) + { + UE_LOG( LogDemo, Log, TEXT( "UDemoNetDriver::ReadStreamingLevelMetadata: GameInstance is null." ) ); + return; + } + + if ( MetadataAr != nullptr ) + { + FNetworkDemoMetadataHeader MetadataHeader; + + (*MetadataAr) << MetadataHeader; + + FString Error; + + // Check metadata magic value + if ( MetadataHeader.Magic != NETWORK_DEMO_METADATA_MAGIC ) + { + Error = FString( TEXT( "Demo metadata file is corrupt" ) ); + UE_LOG( LogDemo, Error, TEXT( "UDemoNetDriver::InitConnect: %s" ), *Error ); + GameInstance->HandleDemoPlaybackFailure( EDemoPlayFailure::Corrupt, Error ); + return; + } + + // Check version + if ( MetadataHeader.Version != NETWORK_DEMO_METADATA_VERSION ) + { + Error = FString( TEXT( "Demo metadata file version is incorrect" ) ); + UE_LOG( LogDemo, Error, TEXT( "UDemoNetDriver::InitConnect: %s" ), *Error ); + GameInstance->HandleDemoPlaybackFailure( EDemoPlayFailure::InvalidVersion, Error ); + return; + } + + DemoTotalFrames = MetadataHeader.NumFrames; + DemoTotalTime = MetadataHeader.TotalTime; + + // Read meta data, if it exists, after the world was loaded. + for ( int32 i = 0; i < MetadataHeader.NumStreamingLevels; ++i ) + { + ULevelStreamingKismet* StreamingLevel = NewObject( GetWorld(), NAME_None, RF_NoFlags, NULL ); + + StreamingLevel->bShouldBeLoaded = true; + StreamingLevel->bShouldBeVisible = true; + StreamingLevel->bShouldBlockOnLoad = false; + StreamingLevel->bInitiallyLoaded = true; + StreamingLevel->bInitiallyVisible = true; + + FString PackageName; + FString PackageNameToLoad; + + ( *MetadataAr ) << PackageName; + ( *MetadataAr ) << PackageNameToLoad; + ( *MetadataAr ) << StreamingLevel->LevelTransform; + + StreamingLevel->PackageNameToLoad = FName( *PackageNameToLoad ); + StreamingLevel->SetWorldAssetByPackageName( FName( *PackageName ) ); + + GetWorld()->StreamingLevels.Add( StreamingLevel ); + + UE_LOG( LogDemo, Log, TEXT( " Loading streamingLevel: %s, %s" ), *PackageName, *PackageNameToLoad ); + } + + UE_LOG( LogDemo, Log, TEXT( "Starting demo playback with full demo and metadata. Filename: %s, Frames: %i." ), *DemoURL.Map, DemoTotalFrames ); + } + else + { + UE_LOG( LogDemo, Log, TEXT( "Starting demo playback with streaming demo, metadata file not found. Filename: %s." ), *DemoURL.Map ); + } +} + /*----------------------------------------------------------------------------- UDemoPendingNetGame. -----------------------------------------------------------------------------*/ @@ -2687,3 +2678,52 @@ void UDemoNetDriver::NotifyGotoTimeFinished(bool bWasSuccessful) UDemoPendingNetGame::UDemoPendingNetGame( const FObjectInitializer& ObjectInitializer ) : Super( ObjectInitializer ) { } + +void UDemoPendingNetGame::Tick( float DeltaTime ) +{ + // Replays don't need to do anything here +} + +void UDemoPendingNetGame::SendJoin() +{ + // Don't send a join request to a replay +} + +void UDemoPendingNetGame::LoadMapCompleted(UEngine* Engine, FWorldContext& Context, bool bLoadedMapSuccessfully, const FString& LoadMapError) +{ +#if !( UE_BUILD_SHIPPING || UE_BUILD_TEST ) + if ( CVarDemoForceFailure.GetValueOnGameThread() == 2 ) + { + bLoadedMapSuccessfully = false; + } +#endif + + // If we have a demo pending net game we should have a demo net driver + check(DemoNetDriver); + + if ( !bLoadedMapSuccessfully ) + { + DemoNetDriver->StopDemo(); + + // If we don't have a world that means we failed loading the new world. + // Since there is no world, we must free the net driver ourselves + // Technically the pending net game should handle it, but things aren't quite setup properly to handle that either + if ( Context.World() == NULL ) + { + GEngine->DestroyNamedNetDriver( Context.PendingNetGame, DemoNetDriver->NetDriverName ); + } + + Context.PendingNetGame = NULL; + + GEngine->BrowseToDefaultMap( Context ); + + UE_LOG( LogDemo, Error, TEXT( "UDemoPendingNetGame::HandlePostLoadMap: LoadMap failed: %s" ), *LoadMapError ); + if ( Context.OwningGameInstance ) + { + Context.OwningGameInstance->HandleDemoPlaybackFailure( EDemoPlayFailure::Generic, FString( TEXT( "LoadMap failed" ) ) ); + } + return; + } + + DemoNetDriver->PendingNetGameLoadMapCompleted(); +} diff --git a/Engine/Source/Runtime/Engine/Private/GameViewportClient.cpp b/Engine/Source/Runtime/Engine/Private/GameViewportClient.cpp index da2e75e8a12b..fcb4645e0297 100644 --- a/Engine/Source/Runtime/Engine/Private/GameViewportClient.cpp +++ b/Engine/Source/Runtime/Engine/Private/GameViewportClient.cpp @@ -35,6 +35,7 @@ #include "IMovieSceneCapture.h" #include "MovieSceneCaptureSettings.h" #include "ActorEditorUtils.h" +#include "ComponentRecreateRenderStateContext.h" #define LOCTEXT_NAMESPACE "GameViewport" @@ -57,9 +58,6 @@ FSimpleMulticastDelegate UGameViewportClient::CreatedDelegate; /** A list of all the stat names which are enabled for this viewport (static so they persist between runs) */ TArray UGameViewportClient::EnabledStats; -/** The number of GameViewportClients which have enabled 'show collision' */ -int32 UGameViewportClient::NumViewportsShowingCollision = 0; - /** Those sound stat flags which are enabled on this viewport */ FViewportClient::ESoundShowFlags::Type UGameViewportClient::SoundShowFlags = FViewportClient::ESoundShowFlags::Disabled; @@ -1376,7 +1374,7 @@ void UGameViewportClient::LostFocus(FViewport* InViewport) // We need to reset some key inputs, since keyup events will sometimes not be processed (such as going into immersive/maximized mode). // Resetting them will prevent them from "sticking" UWorld* const ViewportWorld = GetWorld(); - if (ViewportWorld) + if (ViewportWorld && !ViewportWorld->bIsTearingDown) { for (FConstPlayerControllerIterator Iterator = ViewportWorld->GetPlayerControllerIterator(); Iterator; ++Iterator) { @@ -2173,26 +2171,6 @@ bool UGameViewportClient::HandleForceFullscreenCommand( const TCHAR* Cmd, FOutpu return true; } -/** Contains the previous state of a primitive before turning on collision visibility */ -struct CollVisibilityState -{ - bool bHiddenInGame; - bool bVisible; - - CollVisibilityState(bool InHidden, bool InVisible) : - bHiddenInGame(InHidden), - bVisible(InVisible) - { - } -}; - -typedef TMap, CollVisibilityState> CollisionComponentVisibilityMap; -CollisionComponentVisibilityMap& GetCollisionComponentVisibilityMap() -{ - static CollisionComponentVisibilityMap Mapping; - return Mapping; -} - bool UGameViewportClient::HandleShowCommand( const TCHAR* Cmd, FOutputDevice& Ar, UWorld* InWorld ) { #if UE_BUILD_SHIPPING @@ -2384,62 +2362,17 @@ void UGameViewportClient::ToggleShowCollision() EngineShowFlags.SetVolumes(false); ToggleShowVolumes(); } - - NumViewportsShowingCollision++; - if (World != nullptr) - { - ShowCollisionOnSpawnedActorsDelegateHandle = World->AddOnActorSpawnedHandler(FOnActorSpawned::FDelegate::CreateUObject(this, &UGameViewportClient::ShowCollisionOnSpawnedActors)); - } } - else + + if (World != nullptr) { - NumViewportsShowingCollision--; - check(NumViewportsShowingCollision >= 0); - if (World != nullptr) - { - World->RemoveOnActorSpawnedHandler(ShowCollisionOnSpawnedActorsDelegateHandle); - } + // Tell engine to create proxies for hidden components, so we can still draw collision + World->bCreateRenderStateForHiddenComponents = bIsShowingCollision; + + // Need to recreate scene proxies when this flag changes. + FGlobalComponentRecreateRenderStateContext Recreate; } - CollisionComponentVisibilityMap& Mapping = GetCollisionComponentVisibilityMap(); - - // Restore state to any object in the map above - for (CollisionComponentVisibilityMap::TIterator It(Mapping); It; ++It) - { - TWeakObjectPtr& PrimitiveComponent = It.Key(); - if (PrimitiveComponent.IsValid()) - { - const CollVisibilityState& VisState = It.Value(); - PrimitiveComponent->SetHiddenInGame(VisState.bHiddenInGame); - PrimitiveComponent->SetVisibility(VisState.bVisible); - } - } - Mapping.Empty(); - - if (World == nullptr) - { - return; - } - - if (NumViewportsShowingCollision > 0) - { - for (TObjectIterator It; It; ++It) - { - UPrimitiveComponent* PrimitiveComponent = *It; - if (!PrimitiveComponent->IsVisible() && PrimitiveComponent->IsCollisionEnabled() && PrimitiveComponent->GetScene() == World->Scene) - { - AActor* Owner = PrimitiveComponent->GetOwner(); - - if (Owner && Owner->GetWorld() && Owner->GetWorld()->IsGameWorld() && !FActorEditorUtils::IsABuilderBrush(Owner)) - { - // Save state before modifying the collision visibility - Mapping.Add(PrimitiveComponent, CollVisibilityState(PrimitiveComponent->bHiddenInGame, PrimitiveComponent->bVisible)); - PrimitiveComponent->SetHiddenInGame(false); - PrimitiveComponent->SetVisibility(true); - } - } - } - } #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) if (EngineShowFlags.Collision) @@ -2467,28 +2400,6 @@ void UGameViewportClient::ToggleShowCollision() #endif } -void UGameViewportClient::ShowCollisionOnSpawnedActors(AActor* Actor) -{ - CollisionComponentVisibilityMap& Mapping = GetCollisionComponentVisibilityMap(); - - TInlineComponentArray Components; - check(Actor != nullptr); - Actor->GetComponents(Components); - - for (auto Component : Components) - { - if (!Mapping.Contains(Component) && !Component->IsVisible() && Component->IsCollisionEnabled() && Component->GetScene() == GetWorld()->Scene) - { - check(Component->GetOwner() && Component->GetOwner()->GetWorld() && Component->GetOwner()->GetWorld()->IsGameWorld()); - - // Save state before modifying the collision visibility - Mapping.Add(Component, CollVisibilityState(Component->bHiddenInGame, Component->bVisible)); - Component->SetHiddenInGame(false); - Component->SetVisibility(true); - } - } -} - bool UGameViewportClient::HandleShowLayerCommand( const TCHAR* Cmd, FOutputDevice& Ar, UWorld* InWorld ) { FString LayerName = FParse::Token(Cmd, 0); diff --git a/Engine/Source/Runtime/Engine/Private/Materials/MaterialExpressions.cpp b/Engine/Source/Runtime/Engine/Private/Materials/MaterialExpressions.cpp index 75a4d5dd46a5..d25a384234cf 100644 --- a/Engine/Source/Runtime/Engine/Private/Materials/MaterialExpressions.cpp +++ b/Engine/Source/Runtime/Engine/Private/Materials/MaterialExpressions.cpp @@ -140,6 +140,7 @@ #include "Materials/MaterialExpressionDistanceFieldGradient.h" #include "Materials/MaterialFunction.h" #include "Materials/MaterialParameterCollection.h" +#include "Materials/MaterialExpressionClearCoatNormalCustomOutput.h" #include "EditorSupportDelegates.h" #include "MaterialCompiler.h" @@ -10062,4 +10063,55 @@ void UMaterialExpressionTangentOutput::GetCaption(TArray& OutCaptions) } #endif // WITH_EDITOR +/////////////////////////////////////////////////////////////////////////////// +// Clear Coat Custom Normal Input +/////////////////////////////////////////////////////////////////////////////// + +UMaterialExpressionClearCoatNormalCustomOutput::UMaterialExpressionClearCoatNormalCustomOutput(const FObjectInitializer& ObjectInitializer) +: Super(ObjectInitializer) +{ + // Structure to hold one-time initialization + struct FConstructorStatics + { + FText NAME_Utility; + FConstructorStatics() + : NAME_Utility(LOCTEXT("Utility", "Utility")) + { + } + }; + static FConstructorStatics ConstructorStatics; + + MenuCategories.Add(ConstructorStatics.NAME_Utility); + bCollapsed = true; + + // No outputs + Outputs.Reset(); +} + +#if WITH_EDITOR +int32 UMaterialExpressionClearCoatNormalCustomOutput::Compile(class FMaterialCompiler* Compiler, int32 OutputIndex, int32 MultiplexIndex) +{ + if (Input.Expression) + { + return Compiler->CustomOutput(this, OutputIndex, Input.Compile(Compiler, MultiplexIndex)); + } + else + { + return CompilerError(Compiler, TEXT("Input missing")); + } + return INDEX_NONE; +} + + +void UMaterialExpressionClearCoatNormalCustomOutput::GetCaption(TArray& OutCaptions) const +{ + OutCaptions.Add(FString(TEXT("ClearCoatBottomNormal"))); +} +#endif // WITH_EDITOR + +FExpressionInput* UMaterialExpressionClearCoatNormalCustomOutput::GetInput(int32 InputIndex) +{ + return &Input; +} + #undef LOCTEXT_NAMESPACE diff --git a/Engine/Source/Runtime/Engine/Private/Particles/ParticleComponents.cpp b/Engine/Source/Runtime/Engine/Private/Particles/ParticleComponents.cpp index 58a25dd32803..ca08e4a32ad5 100644 --- a/Engine/Source/Runtime/Engine/Private/Particles/ParticleComponents.cpp +++ b/Engine/Source/Runtime/Engine/Private/Particles/ParticleComponents.cpp @@ -5720,10 +5720,15 @@ void UParticleSystemComponent::InitializeSystem() // Don't warn in a commandlet, we're expected not to have a scene / FX system. if (!IsRunningCommandlet() && !IsRunningDedicatedServer()) { - UE_LOG(LogParticles,Warning,TEXT("InitializeSystem called on an unregistered component. Template=%s Component=%s"), - Template ? *Template->GetPathName() : TEXT("NULL"), - *GetPathName() - ); + // We're also not expected to have a scene / FX system when we belong to an inactive world. + UWorld* OwnerWorld = GetWorld(); + if (!OwnerWorld || OwnerWorld->WorldType != EWorldType::Inactive) + { + UE_LOG(LogParticles,Warning,TEXT("InitializeSystem called on an unregistered component. Template=%s Component=%s"), + Template ? *Template->GetPathName() : TEXT("NULL"), + *GetPathName() + ); + } } return; } diff --git a/Engine/Source/Runtime/Engine/Private/PendingNetGame.cpp b/Engine/Source/Runtime/Engine/Private/PendingNetGame.cpp index 5d2b8445f3b3..ac21135c028d 100644 --- a/Engine/Source/Runtime/Engine/Private/PendingNetGame.cpp +++ b/Engine/Source/Runtime/Engine/Private/PendingNetGame.cpp @@ -100,6 +100,28 @@ void UPendingNetGame::AddReferencedObjects(UObject* InThis, FReferenceCollector& Super::AddReferencedObjects( This, Collector ); } +void UPendingNetGame::LoadMapCompleted(UEngine* Engine, FWorldContext& Context, bool bLoadedMapSuccessfully, const FString& LoadMapError) +{ + if (!bLoadedMapSuccessfully || LoadMapError != TEXT("")) + { + // we can't guarantee the current World is in a valid state, so travel to the default map + Engine->BrowseToDefaultMap(Context); + Engine->BroadcastTravelFailure(Context.World(), ETravelFailure::LoadMapFailure, LoadMapError); + check(Context.World() != NULL); + } + else + { + // Show connecting message, cause precaching to occur. + Engine->TransitionType = TT_Connecting; + + Engine->RedrawViewports(); + + // Send join. + Context.PendingNetGame->SendJoin(); + Context.PendingNetGame->NetDriver = NULL; + } +} + EAcceptConnection::Type UPendingNetGame::NotifyAcceptingConnection() { return EAcceptConnection::Reject; diff --git a/Engine/Source/Runtime/Engine/Private/PlayerCameraManager.cpp b/Engine/Source/Runtime/Engine/Private/PlayerCameraManager.cpp index 4218cd87ef2d..17ae9d1b1169 100644 --- a/Engine/Source/Runtime/Engine/Private/PlayerCameraManager.cpp +++ b/Engine/Source/Runtime/Engine/Private/PlayerCameraManager.cpp @@ -592,13 +592,12 @@ UCameraModifier* APlayerCameraManager::FindCameraModifierByClass(TSubclassOfGetValueOnGameThread() != 0) : 0); + } + { static const auto CVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("Compat.UseDXT5NormalMaps")); Input.Environment.SetDefine(TEXT("DXT5_NORMALMAPS"), CVar ? (CVar->GetValueOnGameThread() != 0) : 0); diff --git a/Engine/Source/Runtime/Engine/Private/SimpleConstructionScript.cpp b/Engine/Source/Runtime/Engine/Private/SimpleConstructionScript.cpp index 558a93f496aa..555dfdbdfdaa 100644 --- a/Engine/Source/Runtime/Engine/Private/SimpleConstructionScript.cpp +++ b/Engine/Source/Runtime/Engine/Private/SimpleConstructionScript.cpp @@ -896,9 +896,10 @@ USceneComponent* USimpleConstructionScript::GetSceneRootComponentTemplate(USCS_N for(int32 StackIndex = 0; StackIndex < BPStack.Num(); ++StackIndex) { - if(BPStack[StackIndex] && BPStack[StackIndex]->SimpleConstructionScript) + if(BPStack[StackIndex] && BPStack[StackIndex]->SimpleConstructionScript && !SCSStack.Contains(BPStack[StackIndex]->SimpleConstructionScript)) { - SCSStack.AddUnique(BPStack[StackIndex]->SimpleConstructionScript); + // UBlueprint::GetBlueprintHierarchyFromClass returns first children then parents. So we need to revert the order. + SCSStack.Insert(BPStack[StackIndex]->SimpleConstructionScript, 0); } } diff --git a/Engine/Source/Runtime/Engine/Private/Slate/SceneViewport.cpp b/Engine/Source/Runtime/Engine/Private/Slate/SceneViewport.cpp index ebd6d42e5396..888dac4cf687 100644 --- a/Engine/Source/Runtime/Engine/Private/Slate/SceneViewport.cpp +++ b/Engine/Source/Runtime/Engine/Private/Slate/SceneViewport.cpp @@ -1364,7 +1364,7 @@ void FSceneViewport::EnqueueBeginRenderFrame() // If we dont have the ViewportRHI then we need to get it before rendering // Note, we need ViewportRHI even if UseSeparateRenderTarget() is true when stereo rendering // is enabled. - if( !IsValidRef(ViewportRHI) && (!UseSeparateRenderTarget() || (GEngine->StereoRenderingDevice.IsValid())) ) + if (!IsValidRef(ViewportRHI) && (!UseSeparateRenderTarget() || (GEngine->StereoRenderingDevice.IsValid() && GEngine->StereoRenderingDevice->IsStereoEnabled()))) { // Get the viewport for this window from the renderer so we can render directly to the backbuffer TSharedPtr Renderer = FSlateApplication::Get().GetRenderer(); diff --git a/Engine/Source/Runtime/Engine/Private/TickTaskManager.cpp b/Engine/Source/Runtime/Engine/Private/TickTaskManager.cpp index bb1be3baaf6a..c8250acf8def 100644 --- a/Engine/Source/Runtime/Engine/Private/TickTaskManager.cpp +++ b/Engine/Source/Runtime/Engine/Private/TickTaskManager.cpp @@ -815,7 +815,7 @@ public: { SCOPE_CYCLE_COUNTER(STAT_ScheduleCooldowns); - TickFunctionsToReschedule.Sort([](const FTickScheduleDetails& A, const FTickScheduleDetails& B) + TickFunctionsToReschedule.Sort([](const FTickScheduleDetails& A, const FTickScheduleDetails& B) { return A.Cooldown < B.Cooldown; }); @@ -830,13 +830,53 @@ public: if ((CumulativeCooldown + ComparisonTickFunction->RelativeTickCooldown) > CooldownTime) { FTickFunction* TickFunction = TickFunctionsToReschedule[RescheduleIndex].TickFunction; + if (TickFunction->TickState == FTickFunction::ETickState::Enabled) + { + if (TickFunctionsToReschedule[RescheduleIndex].bDeferredRemove) + { + verify(AllEnabledTickFunctions.Remove(TickFunction) == 1); + } + TickFunction->TickState = FTickFunction::ETickState::CoolingDown; + TickFunction->RelativeTickCooldown = CooldownTime - CumulativeCooldown; + + if (PrevComparisonTickFunction) + { + PrevComparisonTickFunction->Next = TickFunction; + } + else + { + check(ComparisonTickFunction == AllCoolingDownTickFunctions.Head); + AllCoolingDownTickFunctions.Head = TickFunction; + } + TickFunction->Next = ComparisonTickFunction; + PrevComparisonTickFunction = TickFunction; + ComparisonTickFunction->RelativeTickCooldown -= TickFunction->RelativeTickCooldown; + CumulativeCooldown += TickFunction->RelativeTickCooldown; + } + ++RescheduleIndex; + } + else + { + CumulativeCooldown += ComparisonTickFunction->RelativeTickCooldown; + PrevComparisonTickFunction = ComparisonTickFunction; + ComparisonTickFunction = ComparisonTickFunction->Next; + } + } + for ( ; RescheduleIndex < TickFunctionsToReschedule.Num(); ++RescheduleIndex) + { + FTickFunction* TickFunction = TickFunctionsToReschedule[RescheduleIndex].TickFunction; + if (TickFunction->TickState == FTickFunction::ETickState::Enabled) + { if (TickFunctionsToReschedule[RescheduleIndex].bDeferredRemove) { verify(AllEnabledTickFunctions.Remove(TickFunction) == 1); } + const float CooldownTime = TickFunctionsToReschedule[RescheduleIndex].Cooldown; + TickFunction->TickState = FTickFunction::ETickState::CoolingDown; TickFunction->RelativeTickCooldown = CooldownTime - CumulativeCooldown; + TickFunction->Next = nullptr; if (PrevComparisonTickFunction) { PrevComparisonTickFunction->Next = TickFunction; @@ -846,47 +886,13 @@ public: check(ComparisonTickFunction == AllCoolingDownTickFunctions.Head); AllCoolingDownTickFunctions.Head = TickFunction; } - TickFunction->Next = ComparisonTickFunction; PrevComparisonTickFunction = TickFunction; - ComparisonTickFunction->RelativeTickCooldown -= TickFunction->RelativeTickCooldown; + CumulativeCooldown += TickFunction->RelativeTickCooldown; - ++RescheduleIndex; } - else - { - CumulativeCooldown += ComparisonTickFunction->RelativeTickCooldown; - PrevComparisonTickFunction = ComparisonTickFunction; - ComparisonTickFunction = ComparisonTickFunction->Next; - } - } - for ( ; RescheduleIndex < TickFunctionsToReschedule.Num(); ++RescheduleIndex) - { - FTickFunction* TickFunction = TickFunctionsToReschedule[RescheduleIndex].TickFunction; - if (TickFunctionsToReschedule[RescheduleIndex].bDeferredRemove) - { - verify(AllEnabledTickFunctions.Remove(TickFunction) == 1); - } - const float CooldownTime = TickFunctionsToReschedule[RescheduleIndex].Cooldown; - - TickFunction->TickState = FTickFunction::ETickState::CoolingDown; - TickFunction->RelativeTickCooldown = CooldownTime - CumulativeCooldown; - - TickFunction->Next = nullptr; - if (PrevComparisonTickFunction) - { - PrevComparisonTickFunction->Next = TickFunction; - } - else - { - check(ComparisonTickFunction == AllCoolingDownTickFunctions.Head); - AllCoolingDownTickFunctions.Head = TickFunction; - } - PrevComparisonTickFunction = TickFunction; - - CumulativeCooldown += TickFunction->RelativeTickCooldown; } TickFunctionsToReschedule.Reset(); - } + } } /* Queue all tick functions for execution */ diff --git a/Engine/Source/Runtime/Engine/Private/UnrealEngine.cpp b/Engine/Source/Runtime/Engine/Private/UnrealEngine.cpp index 67f24136b426..05a7b049218e 100644 --- a/Engine/Source/Runtime/Engine/Private/UnrealEngine.cpp +++ b/Engine/Source/Runtime/Engine/Private/UnrealEngine.cpp @@ -1443,6 +1443,20 @@ void LoadSpecialMaterial(const FString& MaterialName, UMaterial*& Material, bool } +template +void LoadEngineClass(const FStringClassReference& ClassName, TSubclassOf& EngineClassRef) +{ + if ( EngineClassRef == nullptr ) + { + EngineClassRef = LoadClass(nullptr, *ClassName.ToString()); + if (EngineClassRef == nullptr) + { + EngineClassRef = ClassType::StaticClass(); + UE_LOG(LogEngine, Error, TEXT("Failed to load '%s', falling back to '%s'"), *ClassName.ToString(), *EngineClassRef->GetName()); + } + } +} + /** * Loads all Engine object references from their corresponding config entries. */ @@ -1516,9 +1530,9 @@ void UEngine::InitializeObjectReferences() } if( HighFrequencyNoiseTexture == NULL ) - { + { HighFrequencyNoiseTexture = LoadObject(NULL, *HighFrequencyNoiseTextureName.ToString(), NULL, LOAD_None, NULL); - } + } if( DefaultBokehTexture == NULL ) { @@ -1552,52 +1566,15 @@ void UEngine::InitializeObjectReferences() checkf(DefaultPhysMaterial != NULL, TEXT("The default material (%s) is not found. Please make sure you have default material set up correctly."), *DefaultPhysMaterialName.ToString()); } - if ( ConsoleClass == NULL ) - { - ConsoleClass = LoadClass(NULL, *ConsoleClassName.ToString(), NULL, LOAD_None, NULL); - } - - if ( GameViewportClientClass == NULL ) - { - GameViewportClientClass = LoadClass(NULL, *GameViewportClientClassName.ToString(), NULL, LOAD_None, NULL); - - checkf(GameViewportClientClass != NULL, TEXT("Engine config value GameViewportClientClassName is not a valid class name.")); - } - - if ( LocalPlayerClass == NULL ) - { - LocalPlayerClass = LoadClass(NULL, *LocalPlayerClassName.ToString(), NULL, LOAD_None, NULL); - } - - if ( WorldSettingsClass == NULL ) - { - WorldSettingsClass = LoadClass(NULL, *WorldSettingsClassName.ToString(), NULL, LOAD_None, NULL); - } - - if ( NavigationSystemClass == NULL ) - { - NavigationSystemClass = LoadClass(NULL, *NavigationSystemClassName.ToString(), NULL, LOAD_None, NULL); - } - - if ( AvoidanceManagerClass == NULL ) - { - AvoidanceManagerClass = LoadClass(NULL, *AvoidanceManagerClassName.ToString(), NULL, LOAD_None, NULL); - } - - if ( PhysicsCollisionHandlerClass == NULL ) - { - PhysicsCollisionHandlerClass = LoadClass(NULL, *PhysicsCollisionHandlerClassName.ToString(), NULL, LOAD_None, NULL); - } - - if ( GameUserSettingsClass == NULL ) - { - GameUserSettingsClass = LoadClass(NULL, *GameUserSettingsClassName.ToString(), NULL, LOAD_None, NULL); - } - - if ( LevelScriptActorClass == NULL ) - { - LevelScriptActorClass = LoadClass(NULL, *LevelScriptActorClassName.ToString(), NULL, LOAD_None, NULL); - } + LoadEngineClass(ConsoleClassName, ConsoleClass); + LoadEngineClass(GameViewportClientClassName, GameViewportClientClass); + LoadEngineClass(LocalPlayerClassName, LocalPlayerClass); + LoadEngineClass(WorldSettingsClassName, WorldSettingsClass); + LoadEngineClass(NavigationSystemClassName, NavigationSystemClass); + LoadEngineClass(AvoidanceManagerClassName, AvoidanceManagerClass); + LoadEngineClass(PhysicsCollisionHandlerClassName, PhysicsCollisionHandlerClass); + LoadEngineClass(GameUserSettingsClassName, GameUserSettingsClass); + LoadEngineClass(LevelScriptActorClassName, LevelScriptActorClass); // set the font object pointers, unless on server if (!IsRunningDedicatedServer()) @@ -9221,24 +9198,7 @@ void UEngine::TickWorldTravel(FWorldContext& Context, float DeltaSeconds) const bool bLoadedMapSuccessfully = LoadMap(Context, Context.PendingNetGame->URL, Context.PendingNetGame, Error); - if (!bLoadedMapSuccessfully || Error != TEXT("")) - { - // we can't guarantee the current World is in a valid state, so travel to the default map - BrowseToDefaultMap(Context); - BroadcastTravelFailure(Context.World(), ETravelFailure::LoadMapFailure, Error); - check(Context.World() != NULL); - } - else - { - // Show connecting message, cause precaching to occur. - TransitionType = TT_Connecting; - - RedrawViewports(); - - // Send join. - Context.PendingNetGame->SendJoin(); - Context.PendingNetGame->NetDriver = NULL; - } + Context.PendingNetGame->LoadMapCompleted(this, Context, bLoadedMapSuccessfully, Error); // Kill the pending level. Context.PendingNetGame = NULL; diff --git a/Engine/Source/Runtime/Engine/Private/UserInterface/Console.cpp b/Engine/Source/Runtime/Engine/Private/UserInterface/Console.cpp index fde9ec9d02f6..79b3b4312c0d 100644 --- a/Engine/Source/Runtime/Engine/Private/UserInterface/Console.cpp +++ b/Engine/Source/Runtime/Engine/Private/UserInterface/Console.cpp @@ -694,6 +694,64 @@ bool UConsole::InputKey_InputLine( int32 ControllerId, FKey Key, EInputEvent Eve return true; } + auto DecrementCursor = [this]() + { + if (AutoCompleteCursor > 0) + { + // move cursor within displayed region + --AutoCompleteCursor; + } + else + { + // can we scroll? + if (AutoCompleteIndex > 0) + { + --AutoCompleteIndex; + } + else + { + // wrap around + AutoCompleteIndex = FMath::Max(0, AutoComplete.Num() - (int32)MAX_AUTOCOMPLETION_LINES - 1); + if (AutoComplete.Num() <= MAX_AUTOCOMPLETION_LINES) + { + AutoCompleteCursor = AutoComplete.Num() + AutoCompleteCursor - 1; + } + else + { + // skip the "x more matches" line when wrapping + AutoCompleteIndex++; + AutoCompleteCursor = MAX_AUTOCOMPLETION_LINES + AutoCompleteCursor - 1; + } + } + bAutoCompleteLocked = false; + } + }; + + auto IncrementCursor = [this]() + { + if (AutoCompleteCursor + 1 < FMath::Min((int32)MAX_AUTOCOMPLETION_LINES, AutoComplete.Num())) + { + // move cursor within displayed region + ++AutoCompleteCursor; + } + else + { + // can be negative + int32 ScrollRegionSize = AutoComplete.Num() - (int32)MAX_AUTOCOMPLETION_LINES; + + // can we scroll? + if (AutoCompleteIndex < ScrollRegionSize) + { + ++AutoCompleteIndex; + } + else + { + // wrap around + AutoCompleteIndex = AutoCompleteCursor = 0; + } + } + }; + // if user input is open if(ConsoleState != NAME_None) { @@ -779,34 +837,13 @@ bool UConsole::InputKey_InputLine( int32 ControllerId, FKey Key, EInputEvent Eve { if(AutoComplete.Num()) { - if (AutoCompleteCursor > 0) + if (ConsoleSettings->bOrderTopToBottom) { - // move cursor within displayed region - --AutoCompleteCursor; + DecrementCursor(); } else { - // can we scroll? - if(AutoCompleteIndex > 0) - { - --AutoCompleteIndex; - } - else - { - // wrap around - AutoCompleteIndex = FMath::Max(0, AutoComplete.Num() - (int32)MAX_AUTOCOMPLETION_LINES - 1); - if (AutoComplete.Num() <= MAX_AUTOCOMPLETION_LINES) - { - AutoCompleteCursor = AutoComplete.Num() + AutoCompleteCursor - 1; - } - else - { - // skip the "x more matches" line when wrapping - AutoCompleteIndex++; - AutoCompleteCursor = MAX_AUTOCOMPLETION_LINES + AutoCompleteCursor - 1; - } - } - bAutoCompleteLocked = false; + IncrementCursor(); } } else @@ -818,42 +855,36 @@ bool UConsole::InputKey_InputLine( int32 ControllerId, FKey Key, EInputEvent Eve } else if( Key == EKeys::Down || Key == EKeys::Tab ) { - if (!bCtrl && AutoComplete.Num()) + if (!bCtrl) { - bool bScroll = AutoComplete.Num() > 1; - - if (Key == EKeys::Tab) + if (AutoComplete.Num()) { - bCaptureKeyInput = true; + bool bScroll = AutoComplete.Num() > 1; - // If this is a repeated tab press, we want to scroll. Otherwise complete the current command - bScroll = bScroll && LastAutoCompletedCommand == TypedStr; - } - - if (bScroll) - { - if (AutoCompleteCursor + 1 < FMath::Min((int32)MAX_AUTOCOMPLETION_LINES, AutoComplete.Num())) + if (Key == EKeys::Tab) { - // move cursor within displayed region - ++AutoCompleteCursor; + bCaptureKeyInput = true; + + // If this is a repeated tab press, we want to scroll. Otherwise complete the current command + bScroll = bScroll && LastAutoCompletedCommand == TypedStr; } - else - { - // can be negative - int32 ScrollRegionSize = AutoComplete.Num() - (int32)MAX_AUTOCOMPLETION_LINES; - // can we scroll? - if (AutoCompleteIndex < ScrollRegionSize) + if (bScroll) + { + if (ConsoleSettings->bOrderTopToBottom) { - ++AutoCompleteIndex; + IncrementCursor(); } else { - // wrap around - AutoCompleteIndex = AutoCompleteCursor = 0; + DecrementCursor(); } } } + else + { + SetAutoCompleteFromHistory(); + } SetInputLineFromAutoComplete(); } @@ -1331,10 +1362,8 @@ void UConsole::PostRender_InputLine(UCanvas* Canvas, FIntPoint UserInputLinePos) Canvas->DrawItem(ConsoleOutline, UserInputLinePos.X + xl - Border, y + yl - Height - Border); // auto completion elements - for(int32 Num = AutoCompleteElements.Num(), i = Num - 1; i >= 0; --i) + auto DrawElement = [&](const FAutoCompleteCommand& AutoCompleteElement, int32 i, int32 Num) { - const FAutoCompleteCommand& AutoCompleteElement = *AutoCompleteElements[i]; - const bool bCursorLineColor = (i == AutoCompleteCursor); const bool bMoreMatches = (Num > MAX_AUTOCOMPLETION_LINES && i == Num - 1); const bool bHistory = AutoCompleteElement.IsHistory(); @@ -1390,6 +1419,21 @@ void UConsole::PostRender_InputLine(UCanvas* Canvas, FIntPoint UserInputLinePos) ConsoleText.Text = FText::FromString(AutoCompleteElement.GetRight()); Canvas->DrawItem( ConsoleText, DescriptionX, y ); y -= yl; + }; + + if (ConsoleSettings->bOrderTopToBottom) + { + for (int32 Num = AutoCompleteElements.Num(), i = Num - 1; i >= 0; --i) + { + DrawElement(*AutoCompleteElements[i], i, Num); + } + } + else + { + for (int32 Num = AutoCompleteElements.Num(), i = 0; i < Num; ++i) + { + DrawElement(*AutoCompleteElements[i], i, Num); + } } } diff --git a/Engine/Source/Runtime/Engine/Private/World.cpp b/Engine/Source/Runtime/Engine/Private/World.cpp index baaadd419020..122acb2fb671 100644 --- a/Engine/Source/Runtime/Engine/Private/World.cpp +++ b/Engine/Source/Runtime/Engine/Private/World.cpp @@ -4869,6 +4869,8 @@ UWorld* FSeamlessTravelHandler::Tick() } } + TArray ActuallyKeptActors; + // rename dynamic actors in the old world's PersistentLevel that we want to keep into the new world for (FActorIterator It(CurrentWorld); It; ++It) { @@ -4886,21 +4888,7 @@ UWorld* FSeamlessTravelHandler::Tick() if (bSameLevel && (bShouldKeep || (TheActor->Role < ROLE_Authority && !bDormant && !TheActor->IsNetStartupActor())) && !TheActor->IsA(ALevelScriptActor::StaticClass())) { It.ClearCurrent(); //@warning: invalidates *It until next iteration - KeepAnnotation.Clear(TheActor); - TheActor->Rename(NULL, LoadedWorld->PersistentLevel); - // if it's a Controller or a Pawn, add it to the appropriate list in the new world's WorldSettings - if (Cast(TheActor)) - { - LoadedWorld->AddController(static_cast(TheActor)); - } - else if (Cast(TheActor)) - { - LoadedWorld->AddPawn(static_cast(TheActor)); - } - // add to new world's actor list and remove from old - LoadedWorld->PersistentLevel->Actors.Add(TheActor); - - TheActor->bActorSeamlessTraveled = true; + ActuallyKeptActors.Add(TheActor); } else { @@ -4921,6 +4909,28 @@ UWorld* FSeamlessTravelHandler::Tick() } } + // Second pass to rename and move actors that need to transition into the new world + // This is done after cleaning up actors that aren't transitioning in case those actors depend on these + // actors being in the same world. + for (AActor* const TheActor : ActuallyKeptActors) + { + KeepAnnotation.Clear(TheActor); + TheActor->Rename(NULL, LoadedWorld->PersistentLevel); + // if it's a Controller or a Pawn, add it to the appropriate list in the new world's WorldSettings + if (Cast(TheActor)) + { + LoadedWorld->AddController(static_cast(TheActor)); + } + else if (Cast(TheActor)) + { + LoadedWorld->AddPawn(static_cast(TheActor)); + } + // add to new world's actor list and remove from old + LoadedWorld->PersistentLevel->Actors.Add(TheActor); + + TheActor->bActorSeamlessTraveled = true; + } + CopyWorldData(); // This copies the net driver too (LoadedWorld now has whatever NetDriver was previously held by CurrentWorld) // only consider session ended if we're making the final switch so that HUD, etc. UI elements stay around until the end diff --git a/Engine/Source/Runtime/Engine/Public/Animation/AnimInstanceProxy.h b/Engine/Source/Runtime/Engine/Public/Animation/AnimInstanceProxy.h index d21d1af944f8..70cac6a981d4 100644 --- a/Engine/Source/Runtime/Engine/Public/Animation/AnimInstanceProxy.h +++ b/Engine/Source/Runtime/Engine/Public/Animation/AnimInstanceProxy.h @@ -171,13 +171,13 @@ public: return LODLevel; } - /** Get the current skeleton we are using */ + /** Get the current skeleton we are using. Note that this will return nullptr outside of pre/post update */ USkeleton* GetSkeleton() { return Skeleton; } - /** Get the current skeletal mesh component we are running on */ + /** Get the current skeletal mesh component we are running on. Note that this will return nullptr outside of pre/post update */ USkeletalMeshComponent* GetSkelMeshComponent() { return SkeletalMeshComponent; @@ -284,6 +284,9 @@ protected: /** Updates the anim graph */ virtual void UpdateAnimationNode(float DeltaSeconds); + /** Called on the game thread pre-evaluate. */ + virtual void PreEvaluateAnimation(UAnimInstance* InAnimInstance); + /** * Evaluate override point * @return true if this function is implemented, false otherwise. @@ -294,6 +297,16 @@ protected: /** Called after update so we can copy any data we need */ virtual void PostUpdate(UAnimInstance* InAnimInstance) const; + /** Copy any UObjects we might be using. Called Pre-update and pre-evaluate. */ + virtual void InitializeObjects(UAnimInstance* InAnimInstance); + + /** + * Clear any UObjects we might be using. Called at the end of the post-evaluate phase. + * This is to ensure that objects are not used by anything apart from animation nodes. + * Please make sure to call the base implementation if this is overridden. + */ + virtual void ClearObjects(); + /** Calls Update(), updates the anim graph, ticks asset players */ void UpdateAnimation(); @@ -471,12 +484,10 @@ private: /** Our anim blueprint generated class */ IAnimClassInterface* AnimClassInterface; - /** Skeleton we are using, only used for comparison purposes */ - UPROPERTY(transient) + /** Skeleton we are using, only used for comparison purposes. Note that this will be nullptr outside of pre/post update */ USkeleton* Skeleton; - /** Skeletal mesh component we are attached to */ - UPROPERTY(transient) + /** Skeletal mesh component we are attached to. Note that this will be nullptr outside of pre/post update */ USkeletalMeshComponent* SkeletalMeshComponent; /** The last time passed into PreUpdate() */ diff --git a/Engine/Source/Runtime/Engine/Public/Animation/AnimSingleNodeInstanceProxy.h b/Engine/Source/Runtime/Engine/Public/Animation/AnimSingleNodeInstanceProxy.h index 4759f41788ea..b98d354e6bc2 100644 --- a/Engine/Source/Runtime/Engine/Public/Animation/AnimSingleNodeInstanceProxy.h +++ b/Engine/Source/Runtime/Engine/Public/Animation/AnimSingleNodeInstanceProxy.h @@ -42,6 +42,8 @@ public: virtual bool Evaluate(FPoseContext& Output) override; virtual void UpdateAnimationNode(float DeltaSeconds) override; virtual void PostUpdate(UAnimInstance* InAnimInstance) const override; + virtual void InitializeObjects(UAnimInstance* InAnimInstance) override; + virtual void ClearObjects() override; void SetPlaying(bool bIsPlaying) { @@ -75,10 +77,6 @@ public: virtual void SetAnimationAsset(UAnimationAsset* NewAsset, USkeletalMeshComponent* MeshComponent, bool bIsLooping, float InPlayRate); - UAnimationAsset* GetCurrentAsset() { return CurrentAsset; } - - UVertexAnimation* GetCurrentVertexAnimation() { return CurrentVertexAnim; } - void UpdateBlendspaceSamples(FVector InBlendInput); void SetCurrentTime(float InCurrentTime) @@ -109,10 +107,15 @@ public: void SetReverse(bool bInReverse); - float GetLength(); - void SetBlendSpaceInput(const FVector& InBlendInput); +#if WITH_EDITOR + bool CanProcessAdditiveAnimations() const + { + return bCanProcessAdditiveAnimations; + } +#endif + private: void InternalBlendSpaceEvaluatePose(class UBlendSpaceBase* BlendSpace, TArray& BlendSampleDataCache, FPoseContext& OutContext); @@ -123,15 +126,13 @@ protected: bool bCanProcessAdditiveAnimations; #endif -private: - /** Current Asset being played **/ - UPROPERTY(transient) + /** Current Asset being played. Note that this will be nullptr outside of pre/post update **/ UAnimationAsset* CurrentAsset; - /** Current vertex anim being played **/ - UPROPERTY(transient) + /** Current vertex anim being played. Note that this will be nullptr outside of pre/post update **/ UVertexAnimation* CurrentVertexAnim; +private: /** Random cached values to play each asset **/ FVector BlendSpaceInput; diff --git a/Engine/Source/Runtime/Engine/Public/SceneInterface.h b/Engine/Source/Runtime/Engine/Public/SceneInterface.h index 8e672ced3fda..6390a04ac2e3 100644 --- a/Engine/Source/Runtime/Engine/Public/SceneInterface.h +++ b/Engine/Source/Runtime/Engine/Public/SceneInterface.h @@ -353,7 +353,7 @@ public: * Initialize the pixel inspector buffers. * @return True if implemented false otherwise. */ - virtual bool InitializePixelInspector(FRenderTarget* BufferFinalColor, FRenderTarget* BufferDepth, FRenderTarget* BufferHDR, FRenderTarget* BufferA, FRenderTarget* BufferBCDE, int32 BufferIndex) + virtual bool InitializePixelInspector(FRenderTarget* BufferFinalColor, FRenderTarget* BufferSceneColor, FRenderTarget* BufferDepth, FRenderTarget* BufferHDR, FRenderTarget* BufferA, FRenderTarget* BufferBCDE, int32 BufferIndex) { return false; } diff --git a/Engine/Source/Runtime/EngineSettings/Classes/ConsoleSettings.h b/Engine/Source/Runtime/EngineSettings/Classes/ConsoleSettings.h index 2cc6d9b17105..923e80df8b51 100644 --- a/Engine/Source/Runtime/EngineSettings/Classes/ConsoleSettings.h +++ b/Engine/Source/Runtime/EngineSettings/Classes/ConsoleSettings.h @@ -79,6 +79,10 @@ class ENGINESETTINGS_API UConsoleSettings UPROPERTY(config, EditAnywhere, Category=Colors, meta=(UIMin="0", UIMax="100", ClampMin="0", ClampMax="100")) float BackgroundOpacityPercentage; + /** Whether we legacy bottom-to-top ordering or regular top-to-bottom ordering */ + UPROPERTY(config, EditAnywhere, Category = AutoComplete) + bool bOrderTopToBottom; + /** The color used for text input. */ UPROPERTY(config, EditAnywhere, Category=Colors) FColor InputColor; diff --git a/Engine/Source/Runtime/GameplayAbilities/Private/Abilities/GameplayAbilityTargetActor.cpp b/Engine/Source/Runtime/GameplayAbilities/Private/Abilities/GameplayAbilityTargetActor.cpp index 98bb9694562d..068502d3e150 100644 --- a/Engine/Source/Runtime/GameplayAbilities/Private/Abilities/GameplayAbilityTargetActor.cpp +++ b/Engine/Source/Runtime/GameplayAbilities/Private/Abilities/GameplayAbilityTargetActor.cpp @@ -135,11 +135,6 @@ bool AGameplayAbilityTargetActor::IsNetRelevantFor(const AActor* RealViewer, con return Super::IsNetRelevantFor(RealViewer, ViewTarget, SrcLocation); } -bool AGameplayAbilityTargetActor::GetReplicates() const -{ - return bReplicates; -} - bool AGameplayAbilityTargetActor::OnReplicatedTargetDataReceived(FGameplayAbilityTargetDataHandle& Data) const { return true; diff --git a/Engine/Source/Runtime/GameplayAbilities/Private/Abilities/GameplayAbilityWorldReticle.cpp b/Engine/Source/Runtime/GameplayAbilities/Private/Abilities/GameplayAbilityWorldReticle.cpp index e5f1a25bc85b..4c4d5662641d 100644 --- a/Engine/Source/Runtime/GameplayAbilities/Private/Abilities/GameplayAbilityWorldReticle.cpp +++ b/Engine/Source/Runtime/GameplayAbilities/Private/Abilities/GameplayAbilityWorldReticle.cpp @@ -49,11 +49,6 @@ bool AGameplayAbilityWorldReticle::IsNetRelevantFor(const AActor* RealViewer, co return Super::IsNetRelevantFor(RealViewer, ViewTarget, SrcLocation); } -bool AGameplayAbilityWorldReticle::GetReplicates() const -{ - return bReplicates; -} - void AGameplayAbilityWorldReticle::SetIsTargetValid(bool bNewValue) { if (bIsTargetValid != bNewValue) diff --git a/Engine/Source/Runtime/GameplayAbilities/Private/Abilities/Tasks/AbilityTask_VisualizeTargeting.cpp b/Engine/Source/Runtime/GameplayAbilities/Private/Abilities/Tasks/AbilityTask_VisualizeTargeting.cpp index d20cbde4e3c6..13ad5020f1f6 100644 --- a/Engine/Source/Runtime/GameplayAbilities/Private/Abilities/Tasks/AbilityTask_VisualizeTargeting.cpp +++ b/Engine/Source/Runtime/GameplayAbilities/Private/Abilities/Tasks/AbilityTask_VisualizeTargeting.cpp @@ -122,7 +122,7 @@ bool UAbilityTask_VisualizeTargeting::ShouldSpawnTargetActor() const const AGameplayAbilityTargetActor* CDO = CastChecked(TargetClass->GetDefaultObject()); - const bool bReplicates = CDO->GetReplicates(); + const bool bReplicates = CDO->GetIsReplicated(); const bool bIsLocallyControlled = Ability->GetCurrentActorInfo()->IsLocallyControlled(); return (bReplicates || bIsLocallyControlled); diff --git a/Engine/Source/Runtime/GameplayAbilities/Private/Abilities/Tasks/AbilityTask_WaitTargetData.cpp b/Engine/Source/Runtime/GameplayAbilities/Private/Abilities/Tasks/AbilityTask_WaitTargetData.cpp index e1b4b998ed08..528aacb5730d 100644 --- a/Engine/Source/Runtime/GameplayAbilities/Private/Abilities/Tasks/AbilityTask_WaitTargetData.cpp +++ b/Engine/Source/Runtime/GameplayAbilities/Private/Abilities/Tasks/AbilityTask_WaitTargetData.cpp @@ -122,7 +122,7 @@ bool UAbilityTask_WaitTargetData::ShouldSpawnTargetActor() const const AGameplayAbilityTargetActor* CDO = CastChecked(TargetClass->GetDefaultObject()); - const bool bReplicates = CDO->GetReplicates(); + const bool bReplicates = CDO->GetIsReplicated(); const bool bIsLocallyControlled = Ability->GetCurrentActorInfo()->IsLocallyControlled(); const bool bShouldProduceTargetDataOnServer = CDO->ShouldProduceTargetDataOnServer; diff --git a/Engine/Source/Runtime/GameplayAbilities/Public/Abilities/GameplayAbilityTargetActor.h b/Engine/Source/Runtime/GameplayAbilities/Public/Abilities/GameplayAbilityTargetActor.h index 22d287a7a94a..ee0d50e77568 100644 --- a/Engine/Source/Runtime/GameplayAbilities/Public/Abilities/GameplayAbilityTargetActor.h +++ b/Engine/Source/Runtime/GameplayAbilities/Public/Abilities/GameplayAbilityTargetActor.h @@ -59,7 +59,8 @@ public: virtual bool OnReplicatedTargetDataReceived(FGameplayAbilityTargetDataHandle& Data) const; /** Accessor for checking, before instantiating, if this TargetActor will replicate. */ - bool GetReplicates() const; + DEPRECATED(4.12, "Call AActor::GetIsReplicated instead") + bool GetReplicates() const { return GetIsReplicated(); } // ------------------------------ diff --git a/Engine/Source/Runtime/GameplayAbilities/Public/Abilities/GameplayAbilityWorldReticle.h b/Engine/Source/Runtime/GameplayAbilities/Public/Abilities/GameplayAbilityWorldReticle.h index 7deb5ad52073..3f0cc3ccb72d 100644 --- a/Engine/Source/Runtime/GameplayAbilities/Public/Abilities/GameplayAbilityWorldReticle.h +++ b/Engine/Source/Runtime/GameplayAbilities/Public/Abilities/GameplayAbilityWorldReticle.h @@ -31,7 +31,8 @@ public: virtual void Tick(float DeltaSeconds) override; /** Accessor for checking, before instantiating, if this WorldReticle will replicate. */ - bool GetReplicates() const; + DEPRECATED(4.12, "Call AActor::GetIsReplicated instead") + bool GetReplicates() const { return GetIsReplicated(); } // ------------------------------ diff --git a/Engine/Source/Runtime/Landscape/Classes/Materials/MaterialExpressionLandscapeLayerBlend.h b/Engine/Source/Runtime/Landscape/Classes/Materials/MaterialExpressionLandscapeLayerBlend.h index 4b681c32d2d6..a92d67552807 100644 --- a/Engine/Source/Runtime/Landscape/Classes/Materials/MaterialExpressionLandscapeLayerBlend.h +++ b/Engine/Source/Runtime/Landscape/Classes/Materials/MaterialExpressionLandscapeLayerBlend.h @@ -11,7 +11,6 @@ enum ELandscapeLayerBlendType LB_WeightBlend, LB_AlphaBlend, LB_HeightBlend, - LB_MAX, }; USTRUCT() diff --git a/Engine/Source/Runtime/Landscape/Private/LandscapeEdit.cpp b/Engine/Source/Runtime/Landscape/Private/LandscapeEdit.cpp index 55dc83250ee4..52f968883a40 100644 --- a/Engine/Source/Runtime/Landscape/Private/LandscapeEdit.cpp +++ b/Engine/Source/Runtime/Landscape/Private/LandscapeEdit.cpp @@ -79,6 +79,11 @@ void ULandscapeComponent::UpdateCachedBounds() CachedLocalBox += CDI.GetLocalVertex(x, y); } } + if (CachedLocalBox.GetExtent().Z == 0) + { + // expand bounds to avoid flickering issues with zero-size bounds + CachedLocalBox.ExpandBy(FVector(0, 0, 1)); + } // Update collision component bounds ULandscapeHeightfieldCollisionComponent* HFCollisionComponent = CollisionComponent.Get(); diff --git a/Engine/Source/Runtime/Landscape/Private/LandscapeSplines.cpp b/Engine/Source/Runtime/Landscape/Private/LandscapeSplines.cpp index a5ea99f35976..6848e2a079e2 100644 --- a/Engine/Source/Runtime/Landscape/Private/LandscapeSplines.cpp +++ b/Engine/Source/Runtime/Landscape/Private/LandscapeSplines.cpp @@ -125,7 +125,7 @@ public: { // Slight Depth Bias so that the splines show up when they exactly match the target surface // e.g. someone playing with splines on a newly-created perfectly-flat landscape - static const float DepthBias = -0.0001; + static const float DepthBias = 0.0001; const FMatrix& LocalToWorld = GetLocalToWorld(); @@ -1581,8 +1581,15 @@ void ULandscapeSplineControlPoint::UpdateSplinePoints(bool bUpdateCollision, boo Points.Emplace(StartLocation, LeftPos, RightPos, FalloffLeftPos, FalloffRightPos, 1.0f); } - // Update Bounds + // Update bounds Bounds = FBox(0); + + // Sprite bounds + float SpriteScale = FMath::Clamp(Width != 0 ? Width / 2 : SideFalloff / 4, 10, 1000); + Bounds += Location + FVector(0, 0, 0.75f * SpriteScale); + Bounds = Bounds.ExpandBy(SpriteScale); + + // Points bounds for (const FLandscapeSplineInterpPoint& Point : Points) { Bounds += Point.FalloffLeft; diff --git a/Engine/Source/Runtime/Landscape/Private/Materials/MaterialExpressionLandscapeLayerBlend.cpp b/Engine/Source/Runtime/Landscape/Private/Materials/MaterialExpressionLandscapeLayerBlend.cpp index 0c695ef69d89..4a07b24f718b 100644 --- a/Engine/Source/Runtime/Landscape/Private/Materials/MaterialExpressionLandscapeLayerBlend.cpp +++ b/Engine/Source/Runtime/Landscape/Private/Materials/MaterialExpressionLandscapeLayerBlend.cpp @@ -6,6 +6,9 @@ #include "EdGraph/EdGraphNode.h" #include "Engine/Engine.h" #include "EngineGlobals.h" +#if WITH_EDITOR +#include "MaterialGraph/MaterialGraphNode.h" +#endif #define LOCTEXT_NAMESPACE "Landscape" @@ -311,9 +314,9 @@ void UMaterialExpressionLandscapeLayerBlend::PostEditChangeProperty(FPropertyCha const FName PropertyName = PropertyChangedEvent.MemberProperty->GetFName(); if (PropertyName == GET_MEMBER_NAME_CHECKED(UMaterialExpressionLandscapeLayerBlend, Layers)) { - if (GraphNode) + if (UMaterialGraphNode* MatGraphNode = Cast(GraphNode)) { - GraphNode->ReconstructNode(); + MatGraphNode->RecreateAndLinkNode(); } } } diff --git a/Engine/Source/Runtime/Launch/Private/LaunchEngineLoop.cpp b/Engine/Source/Runtime/Launch/Private/LaunchEngineLoop.cpp index 548a0e106f67..03e6024c4932 100644 --- a/Engine/Source/Runtime/Launch/Private/LaunchEngineLoop.cpp +++ b/Engine/Source/Runtime/Launch/Private/LaunchEngineLoop.cpp @@ -1442,8 +1442,10 @@ int32 FEngineLoop::PreInit( const TCHAR* CmdLine ) SlowTask.EnterProgressFrame(10); #if USE_LOCALIZED_PACKAGE_CACHE - // this loads a UObject, so we do this now after objects are brought up (otherwise, it can't load properties from config) - FPackageLocalizationManager::Get().InitializeFromDefaultCache(); + FPackageLocalizationManager::Get().InitializeFromLazyCallback([](FPackageLocalizationManager& InPackageLocalizationManager) + { + InPackageLocalizationManager.InitializeFromCache(MakeShareable(new FEnginePackageLocalizationCache())); + }); #endif // USE_LOCALIZED_PACKAGE_CACHE // Initialize the RHI. @@ -1495,6 +1497,12 @@ int32 FEngineLoop::PreInit( const TCHAR* CmdLine ) // Make sure all UObject classes are registered and default properties have been initialized ProcessNewlyLoadedUObjects(); +#if USE_LOCALIZED_PACKAGE_CACHE + // CoreUObject is definitely available now, so make sure the package localization cache is available + // This may have already been initialized from the CDO creation from ProcessNewlyLoadedUObjects + FPackageLocalizationManager::Get().PerformLazyInitialization(); +#endif // USE_LOCALIZED_PACKAGE_CACHE + // Default materials may have been loaded due to dependencies when loading // classes and class default objects. If not, do so now. UMaterialInterface::InitDefaultMaterials(); @@ -1704,7 +1712,13 @@ int32 FEngineLoop::PreInit( const TCHAR* CmdLine ) #if WITH_EDITOR if ( GIsEditor ) { - UClass* EditorEngineClass = StaticLoadClass( UEditorEngine::StaticClass(), nullptr, TEXT("engine-ini:/Script/Engine.Engine.EditorEngine"), nullptr, LOAD_None, nullptr ); + FString EditorEngineClassName; + GConfig->GetString(TEXT("/Script/Engine.Engine"), TEXT("EditorEngine"), EditorEngineClassName, GEngineIni); + UClass* EditorEngineClass = StaticLoadClass( UEditorEngine::StaticClass(), nullptr, *EditorEngineClassName); + if (EditorEngineClass == nullptr) + { + UE_LOG(LogInit, Fatal, TEXT("Failed to load Editor Engine class '%s'."), *EditorEngineClassName); + } GEngine = GEditor = NewObject(GetTransientPackage(), EditorEngineClass); @@ -1717,7 +1731,15 @@ int32 FEngineLoop::PreInit( const TCHAR* CmdLine ) else #endif { - UClass* EngineClass = StaticLoadClass( UEngine::StaticClass(), nullptr, TEXT("engine-ini:/Script/Engine.Engine.GameEngine"), nullptr, LOAD_None, nullptr ); + FString GameEngineClassName; + GConfig->GetString(TEXT("/Script/Engine.Engine"), TEXT("GameEngine"), GameEngineClassName, GEngineIni); + + UClass* EngineClass = StaticLoadClass( UEngine::StaticClass(), nullptr, *GameEngineClassName); + + if (EngineClass == nullptr) + { + UE_LOG(LogInit, Fatal, TEXT("Failed to load Engine class '%s'."), *GameEngineClassName); + } // must do this here so that the engine object that we create on the next line receives the correct property values GEngine = NewObject(GetTransientPackage(), EngineClass); @@ -2217,14 +2239,26 @@ int32 FEngineLoop::Init() if( !GIsEditor ) { // We're the game. - EngineClass = StaticLoadClass( UGameEngine::StaticClass(), nullptr, TEXT("engine-ini:/Script/Engine.Engine.GameEngine"), nullptr, LOAD_None, nullptr ); + FString GameEngineClassName; + GConfig->GetString(TEXT("/Script/Engine.Engine"), TEXT("GameEngine"), GameEngineClassName, GEngineIni); + EngineClass = StaticLoadClass( UGameEngine::StaticClass(), nullptr, *GameEngineClassName); + if (EngineClass == nullptr) + { + UE_LOG(LogInit, Fatal, TEXT("Failed to load UnrealEd Engine class '%s'."), *GameEngineClassName); + } GEngine = NewObject(GetTransientPackage(), EngineClass); } else { #if WITH_EDITOR // We're UnrealEd. - EngineClass = StaticLoadClass( UUnrealEdEngine::StaticClass(), nullptr, TEXT("engine-ini:/Script/Engine.Engine.UnrealEdEngine"), nullptr, LOAD_None, nullptr ); + FString UnrealEdEngineClassName; + GConfig->GetString(TEXT("/Script/Engine.Engine"), TEXT("UnrealEdEngine"), UnrealEdEngineClassName, GEngineIni); + EngineClass = StaticLoadClass(UUnrealEdEngine::StaticClass(), nullptr, *UnrealEdEngineClassName); + if (EngineClass == nullptr) + { + UE_LOG(LogInit, Fatal, TEXT("Failed to load UnrealEd Engine class '%s'."), *UnrealEdEngineClassName); + } GEngine = GEditor = GUnrealEd = NewObject(GetTransientPackage(), EngineClass); #else check(0); diff --git a/Engine/Source/Runtime/LevelSequence/Private/LevelSequenceObjectReference.cpp b/Engine/Source/Runtime/LevelSequence/Private/LevelSequenceObjectReference.cpp index 70e53ad971a3..7025e1318101 100644 --- a/Engine/Source/Runtime/LevelSequence/Private/LevelSequenceObjectReference.cpp +++ b/Engine/Source/Runtime/LevelSequence/Private/LevelSequenceObjectReference.cpp @@ -30,7 +30,7 @@ FLevelSequenceObjectReference::FLevelSequenceObjectReference(const FUniqueObject UObject* FLevelSequenceObjectReference::Resolve(UObject* InContext) const { - if (ObjectId.IsValid()) + if (ObjectId.IsValid() && InContext != nullptr) { #if WITH_EDITOR int32 PIEInstanceID = InContext->GetOutermost()->PIEInstanceID; diff --git a/Engine/Source/Runtime/LevelSequence/Private/LevelSequenceSpawnRegister.cpp b/Engine/Source/Runtime/LevelSequence/Private/LevelSequenceSpawnRegister.cpp index 3114bf7c72fa..191f42a24293 100644 --- a/Engine/Source/Runtime/LevelSequence/Private/LevelSequenceSpawnRegister.cpp +++ b/Engine/Source/Runtime/LevelSequence/Private/LevelSequenceSpawnRegister.cpp @@ -55,7 +55,9 @@ UObject* FLevelSequenceSpawnRegister::SpawnObject(const FGuid& BindingId, FMovie { SpawnInfo.Name = ActorName; SpawnInfo.ObjectFlags = ObjectFlags; - SpawnInfo.Template = ObjectTemplate; + SpawnInfo.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn; + // @todo: Spawning with a non-CDO template is fraught with issues + //SpawnInfo.Template = ObjectTemplate; } FTransform SpawnTransform; @@ -81,50 +83,15 @@ UObject* FLevelSequenceSpawnRegister::SpawnObject(const FGuid& BindingId, FMovie WorldContext = GWorld; } - // @todo: Remove when instanced components work correctly on spawned templates - TArray TemplateInstanceComponents = ObjectTemplate->GetInstanceComponents(); - ObjectTemplate->ClearInstanceComponents(false); - AActor* SpawnedActor = WorldContext->SpawnActorAbsolute(ObjectTemplate->GetClass(), SpawnTransform, SpawnInfo); if (!SpawnedActor) { return nullptr; } - - // First, duplicate instance components - for (UActorComponent* TemplateComponent : TemplateInstanceComponents) - { - ObjectTemplate->AddInstanceComponent(TemplateComponent); - - UActorComponent* NewComponent = DuplicateObject(TemplateComponent, SpawnedActor, TemplateComponent->GetFName()); - SpawnedActor->AddInstanceComponent(NewComponent); - } - - // Second, attach the components. We do this as a different pass, since instance components may be attached to each other - for (UActorComponent* ActorComp : SpawnedActor->GetInstanceComponents()) - { - USceneComponent* SceneComp = Cast(ActorComp); - if (!SceneComp) - { - continue; - } - - USceneComponent* NewParent = SpawnedActor->GetRootComponent(); - - USceneComponent* OldParent = SceneComp->GetAttachParent(); - if (OldParent) - { - FString PathName = OldParent->GetPathName(OldParent->GetOwner()); - - NewParent = FindObject(SpawnedActor, *PathName); - } - - if (ensure(NewParent)) - { - SceneComp->AttachToComponent(NewParent, FAttachmentTransformRules::KeepRelativeTransform, SceneComp->GetAttachSocketName()); - } - } - + + UEngine::FCopyPropertiesForUnrelatedObjectsParams CopyParams; + SpawnedActor->UnregisterAllComponents(); + UEngine::CopyPropertiesForUnrelatedObjects(ObjectTemplate, SpawnedActor, CopyParams); SpawnedActor->RegisterAllComponents(); // tag this actor so we know it was spawned by sequencer diff --git a/Engine/Source/Runtime/LevelSequence/Public/LevelSequenceActor.h b/Engine/Source/Runtime/LevelSequence/Public/LevelSequenceActor.h index 7dd95391f6be..12842defa965 100644 --- a/Engine/Source/Runtime/LevelSequence/Public/LevelSequenceActor.h +++ b/Engine/Source/Runtime/LevelSequence/Public/LevelSequenceActor.h @@ -9,7 +9,7 @@ /** * Actor responsible for controlling a specific level sequence in the world. */ -UCLASS(Experimental, hideCategories=(Rendering, Physics, LOD, Activation)) +UCLASS(hideCategories=(Rendering, Physics, LOD, Activation)) class LEVELSEQUENCE_API ALevelSequenceActor : public AActor { diff --git a/Engine/Source/Runtime/MovieScene/Public/IMovieSceneTrackInstance.h b/Engine/Source/Runtime/MovieScene/Public/IMovieSceneTrackInstance.h index 0daef89fd169..ebc5259f24e3 100644 --- a/Engine/Source/Runtime/MovieScene/Public/IMovieSceneTrackInstance.h +++ b/Engine/Source/Runtime/MovieScene/Public/IMovieSceneTrackInstance.h @@ -20,6 +20,7 @@ struct EMovieSceneUpdateData float LastPosition; bool bPreroll; bool bJumpCut; + bool bLooped; /** Indicates that this update was caused by the owning movie scene stopping playback due to the active sub-scene being deactivated. */ bool bSubSceneDeactivate; @@ -32,6 +33,7 @@ struct EMovieSceneUpdateData LastPosition = 0.0f; bPreroll = false; bJumpCut = false; + bLooped = false; bSubSceneDeactivate = false; UpdatePass = MSUP_PreUpdate; } @@ -41,6 +43,7 @@ struct EMovieSceneUpdateData LastPosition = InLastPosition; bPreroll = false; bJumpCut = false; + bLooped = false; bSubSceneDeactivate = false; UpdatePass = MSUP_PreUpdate; } diff --git a/Engine/Source/Runtime/MovieSceneCapture/Public/Protocols/ImageSequenceProtocol.h b/Engine/Source/Runtime/MovieSceneCapture/Public/Protocols/ImageSequenceProtocol.h index 07841892848c..73e870be912b 100644 --- a/Engine/Source/Runtime/MovieSceneCapture/Public/Protocols/ImageSequenceProtocol.h +++ b/Engine/Source/Runtime/MovieSceneCapture/Public/Protocols/ImageSequenceProtocol.h @@ -27,7 +27,7 @@ UCLASS(config=EditorPerProjectUserSettings, DisplayName="Image Encoding") class MOVIESCENECAPTURE_API UImageCaptureSettings : public UFrameGrabberProtocolSettings { public: - UImageCaptureSettings(const FObjectInitializer& Init) : UFrameGrabberProtocolSettings(Init), CompressionQuality(75) {} + UImageCaptureSettings(const FObjectInitializer& Init) : UFrameGrabberProtocolSettings(Init), CompressionQuality(100) {} GENERATED_BODY() diff --git a/Engine/Source/Runtime/MovieSceneTracks/MovieSceneTracks.Build.cs b/Engine/Source/Runtime/MovieSceneTracks/MovieSceneTracks.Build.cs index 0365b89c1c9f..c91422b9cbb0 100644 --- a/Engine/Source/Runtime/MovieSceneTracks/MovieSceneTracks.Build.cs +++ b/Engine/Source/Runtime/MovieSceneTracks/MovieSceneTracks.Build.cs @@ -28,10 +28,5 @@ public class MovieSceneTracks : ModuleRules "SlateCore", } ); - - if (UEBuildConfiguration.bBuildEditor == true) - { - PrivateDependencyModuleNames.Add("UnrealEd"); - } } } diff --git a/Engine/Source/Runtime/MovieSceneTracks/Private/Sections/MovieScene3DTransformSection.cpp b/Engine/Source/Runtime/MovieSceneTracks/Private/Sections/MovieScene3DTransformSection.cpp index 831f4c34410d..d4351e2b17a0 100644 --- a/Engine/Source/Runtime/MovieSceneTracks/Private/Sections/MovieScene3DTransformSection.cpp +++ b/Engine/Source/Runtime/MovieSceneTracks/Private/Sections/MovieScene3DTransformSection.cpp @@ -435,7 +435,9 @@ bool UMovieScene3DTransformSection::HasKeys(const FTransformKey& TransformKey) c void UMovieScene3DTransformSection::AddKey(float Time, const FTransformKey& TransformKey, EMovieSceneKeyInterpolation KeyInterpolation) { FRichCurve* KeyCurve = GetCurveForChannelAndAxis(TransformKey.Channel, TransformKey.Axis, Translation, Rotation, Scale); - AddKeyToCurve(*KeyCurve, Time, TransformKey.Value, KeyInterpolation); + + bool bUnwindRotation = TransformKey.Channel == EKey3DTransformChannel::Rotation; + AddKeyToCurve(*KeyCurve, Time, TransformKey.Value, KeyInterpolation, bUnwindRotation); } diff --git a/Engine/Source/Runtime/MovieSceneTracks/Private/TrackInstances/MovieSceneActorReferenceTrackInstance.cpp b/Engine/Source/Runtime/MovieSceneTracks/Private/TrackInstances/MovieSceneActorReferenceTrackInstance.cpp index 9831bbe7584e..64529daa3397 100644 --- a/Engine/Source/Runtime/MovieSceneTracks/Private/TrackInstances/MovieSceneActorReferenceTrackInstance.cpp +++ b/Engine/Source/Runtime/MovieSceneTracks/Private/TrackInstances/MovieSceneActorReferenceTrackInstance.cpp @@ -17,7 +17,8 @@ void FMovieSceneActorReferenceTrackInstance::SaveState(const TArrayGetCurrentValue(Object); InitActorReferenceMap.Add(FObjectKey(Object), ActorReferenceValue); @@ -37,10 +38,13 @@ void FMovieSceneActorReferenceTrackInstance::RestoreState(const TArrayCallFunction(Object, ActorReferenceValue); + TWeakObjectPtr ActorReferenceValue = *InitActorReferenceMap.Find(FObjectKey(Object)); + if (ActorReferenceValue.IsValid()) + { + PropertyBindings->CallFunction(Object, ActorReferenceValue.Get()); + } } } @@ -54,14 +58,17 @@ void FMovieSceneActorReferenceTrackInstance::Update(EMovieSceneUpdateData& Updat FGuid ActorReferenceGuid; if( ActorReferenceTrack->Eval( UpdateData.Position, UpdateData.LastPosition, ActorReferenceGuid ) ) { - AActor* CurrentActor; - AActor** CachedActorPtr = GuidToActorCache.Find( ActorReferenceGuid ); - - if (CachedActorPtr != nullptr) + AActor* CurrentActor = nullptr; + if (GuidToActorCache.Contains(ActorReferenceGuid)) { - CurrentActor = *CachedActorPtr; + TWeakObjectPtr CachedActor = *GuidToActorCache.Find(ActorReferenceGuid); + if (CachedActor.IsValid()) + { + CurrentActor = CachedActor.Get(); + } } - else + + if (CurrentActor == nullptr) { TArray> RuntimeObjectsForGuid; Player.GetRuntimeObjects(SequenceInstance.AsShared(), ActorReferenceGuid, RuntimeObjectsForGuid); @@ -73,15 +80,21 @@ void FMovieSceneActorReferenceTrackInstance::Update(EMovieSceneUpdateData& Updat if (ActorForGuid != nullptr) { CurrentActor = ActorForGuid; - GuidToActorCache.Add(ActorReferenceGuid, CurrentActor); + if (CurrentActor != nullptr) + { + GuidToActorCache.Add(ActorReferenceGuid, CurrentActor); + } } } } - for (auto ObjectPtr : RuntimeObjects) + if (CurrentActor != nullptr) { - UObject* Object = ObjectPtr.Get(); - PropertyBindings->CallFunction(Object, &CurrentActor); + for (auto ObjectPtr : RuntimeObjects) + { + UObject* Object = ObjectPtr.Get(); + PropertyBindings->CallFunction(Object, &CurrentActor); + } } } } diff --git a/Engine/Source/Runtime/MovieSceneTracks/Private/TrackInstances/MovieSceneAudioTrackInstance.cpp b/Engine/Source/Runtime/MovieSceneTracks/Private/TrackInstances/MovieSceneAudioTrackInstance.cpp index 5c9eeb018f32..ed9ecbcb0654 100644 --- a/Engine/Source/Runtime/MovieSceneTracks/Private/TrackInstances/MovieSceneAudioTrackInstance.cpp +++ b/Engine/Source/Runtime/MovieSceneTracks/Private/TrackInstances/MovieSceneAudioTrackInstance.cpp @@ -38,7 +38,8 @@ void FMovieSceneAudioTrackInstance::Update(EMovieSceneUpdateData& UpdateData, co if (Player.GetPlaybackStatus() == EMovieScenePlayerStatus::Playing) { - if (UpdateData.Position > UpdateData.LastPosition) + float LastPosition = UpdateData.bLooped ? UpdateData.Position : UpdateData.LastPosition; + if (UpdateData.Position >= LastPosition) { TMap > AudioSectionsBySectionIndex; for (int32 i = 0; i < AudioSections.Num(); ++i) @@ -68,7 +69,7 @@ void FMovieSceneAudioTrackInstance::Update(EMovieSceneUpdateData& UpdateData, co UMovieSceneAudioSection* AudioSection = MovieSceneAudioSections[i]; if (AudioSection->IsTimeWithinAudioRange(UpdateData.Position)) { - if (!AudioSection->IsTimeWithinAudioRange(UpdateData.LastPosition) || !Component->IsPlaying()) + if (!AudioSection->IsTimeWithinAudioRange(LastPosition) || !Component->IsPlaying()) { PlaySound(AudioSection, Component, UpdateData.Position); } diff --git a/Engine/Source/Runtime/MovieSceneTracks/Private/TrackInstances/MovieSceneLevelVisibilityTrackInstance.cpp b/Engine/Source/Runtime/MovieSceneTracks/Private/TrackInstances/MovieSceneLevelVisibilityTrackInstance.cpp index 8e83f6b68ca1..161e80171b98 100644 --- a/Engine/Source/Runtime/MovieSceneTracks/Private/TrackInstances/MovieSceneLevelVisibilityTrackInstance.cpp +++ b/Engine/Source/Runtime/MovieSceneTracks/Private/TrackInstances/MovieSceneLevelVisibilityTrackInstance.cpp @@ -3,9 +3,6 @@ #include "MovieSceneTracksPrivatePCH.h" #include "MovieSceneLevelVisibilityTrack.h" #include "MovieSceneLevelVisibilityTrackInstance.h" -#if WITH_EDITOR -#include "EditorLevelUtils.h" -#endif FMovieSceneLevelVisibilityTrackInstance::FMovieSceneLevelVisibilityTrackInstance( UMovieSceneLevelVisibilityTrack& InLevelVisibilityTrack ) @@ -89,10 +86,32 @@ bool GetLevelVisibility( ULevelStreaming* Level ) void SetLevelVisibility( ULevelStreaming* Level, bool bVisible ) { #if WITH_EDITOR - UE_LOG( LogMovieScene, Log, TEXT( "Setting Visibility: Level=%s Visible=%s" ), *Level->GetWorldAssetPackageName(), bVisible ? TEXT( "true" ) : TEXT( "false" ) ); if ( GIsEditor && Level->GetWorld()->IsPlayInEditor() == false ) { - EditorLevelUtils::SetLevelVisibility( Level->GetLoadedLevel(), bVisible, false ); + Level->bShouldBeVisibleInEditor = bVisible; + Level->GetWorld()->FlushLevelStreaming(); + + // Iterate over the level's actors + TTransArray& Actors = Level->GetLoadedLevel()->Actors; + for ( int32 ActorIndex = 0; ActorIndex < Actors.Num(); ++ActorIndex ) + { + AActor* Actor = Actors[ActorIndex]; + if ( Actor ) + { + if (Actor->bHiddenEdLevel == bVisible ) + { + Actor->bHiddenEdLevel = !bVisible; + if ( bVisible ) + { + Actor->ReregisterAllComponents(); + } + else + { + Actor->UnregisterAllComponents(); + } + } + } + } } else #endif diff --git a/Engine/Source/Runtime/MovieSceneTracks/Private/TrackInstances/MovieSceneParticleTrackInstance.cpp b/Engine/Source/Runtime/MovieSceneTracks/Private/TrackInstances/MovieSceneParticleTrackInstance.cpp index 606267855879..7d4260bd7494 100644 --- a/Engine/Source/Runtime/MovieSceneTracks/Private/TrackInstances/MovieSceneParticleTrackInstance.cpp +++ b/Engine/Source/Runtime/MovieSceneTracks/Private/TrackInstances/MovieSceneParticleTrackInstance.cpp @@ -29,7 +29,8 @@ void FMovieSceneParticleTrackInstance::Update(EMovieSceneUpdateData& UpdateData, // @todo Sequencer We need something analagous to Matinee 1's particle replay tracks // What we have here is simple toggling/triggering - if (UpdateData.Position > UpdateData.LastPosition && Player.GetPlaybackStatus() == EMovieScenePlayerStatus::Playing) + float LastPosition = UpdateData.bLooped ? UpdateData.Position : UpdateData.LastPosition; + if (UpdateData.Position >= LastPosition && Player.GetPlaybackStatus() == EMovieScenePlayerStatus::Playing) { const TArray Sections = ParticleTrack->GetAllParticleSections(); EParticleKey::Type ParticleKey = EParticleKey::Deactivate; @@ -45,7 +46,7 @@ void FMovieSceneParticleTrackInstance::Update(EMovieSceneUpdateData& UpdateData, if ( ParticleKeyCurve.IsKeyHandleValid( PreviousHandle ) ) { FIntegralKey& PreviousKey = ParticleKeyCurve.GetKey( PreviousHandle ); - if ( PreviousKey.Time >= UpdateData.LastPosition ) + if ( PreviousKey.Time >= LastPosition ) { ParticleKey = (EParticleKey::Type)PreviousKey.Value; bKeyFound = true; diff --git a/Engine/Source/Runtime/MovieSceneTracks/Private/TrackInstances/MovieSceneSkeletalAnimationTrackInstance.cpp b/Engine/Source/Runtime/MovieSceneTracks/Private/TrackInstances/MovieSceneSkeletalAnimationTrackInstance.cpp index 029487760d04..15758d10f7fa 100644 --- a/Engine/Source/Runtime/MovieSceneTracks/Private/TrackInstances/MovieSceneSkeletalAnimationTrackInstance.cpp +++ b/Engine/Source/Runtime/MovieSceneTracks/Private/TrackInstances/MovieSceneSkeletalAnimationTrackInstance.cpp @@ -321,6 +321,6 @@ void FMovieSceneSkeletalAnimationTrackInstance::PreviewSetAnimPosition(USkeletal bool FMovieSceneSkeletalAnimationTrackInstance::ShouldUsePreviewPlayback(class IMovieScenePlayer& Player, UObject* RuntimeObject) const { // we also use PreviewSetAnimPosition in PIE when not playing, as we can preview in PIE - bool bIsNotInPIEOrNotPlaying = (RuntimeObject && !RuntimeObject->GetWorld()->HasBegunPlay()) || Player.GetPlaybackStatus() != EMovieScenePlayerStatus::Playing; + bool bIsNotInPIEOrNotPlaying = (RuntimeObject && RuntimeObject->GetWorld() && !RuntimeObject->GetWorld()->HasBegunPlay()) || Player.GetPlaybackStatus() != EMovieScenePlayerStatus::Playing; return GIsEditor && bIsNotInPIEOrNotPlaying; } diff --git a/Engine/Source/Runtime/MovieSceneTracks/Private/TrackInstances/MovieSceneSubTrackInstance.cpp b/Engine/Source/Runtime/MovieSceneTracks/Private/TrackInstances/MovieSceneSubTrackInstance.cpp index 8b516341a397..74e882926ac4 100644 --- a/Engine/Source/Runtime/MovieSceneTracks/Private/TrackInstances/MovieSceneSubTrackInstance.cpp +++ b/Engine/Source/Runtime/MovieSceneTracks/Private/TrackInstances/MovieSceneSubTrackInstance.cpp @@ -192,9 +192,12 @@ void FMovieSceneSubTrackInstance::Update(EMovieSceneUpdateData& UpdateData, cons for ( TWeakObjectPtr LastSubSection : LastTraversedSections ) { - if ( TraversedSections.Contains( LastSubSection.Get() ) == false ) + if (LastSubSection.IsValid()) { - UpdateSection( UpdateData, Player, LastSubSection.Get(), true ); + if ( TraversedSections.Contains( LastSubSection.Get() ) == false ) + { + UpdateSection( UpdateData, Player, LastSubSection.Get(), true ); + } } } LastTraversedSections.Empty(); diff --git a/Engine/Source/Runtime/MovieSceneTracks/Public/TrackInstances/MovieSceneActorReferenceTrackInstance.h b/Engine/Source/Runtime/MovieSceneTracks/Public/TrackInstances/MovieSceneActorReferenceTrackInstance.h index 16f1c90f3a40..a0a7424de4af 100644 --- a/Engine/Source/Runtime/MovieSceneTracks/Public/TrackInstances/MovieSceneActorReferenceTrackInstance.h +++ b/Engine/Source/Runtime/MovieSceneTracks/Public/TrackInstances/MovieSceneActorReferenceTrackInstance.h @@ -36,7 +36,8 @@ private: TSharedPtr PropertyBindings; /** Map from object to initial state */ - TMap InitActorReferenceMap; + TMap> InitActorReferenceMap; - TMap GuidToActorCache; + /** Map from guid to cached actor */ + TMap> GuidToActorCache; }; diff --git a/Engine/Source/Runtime/OpenGLDrv/Private/Android/AndroidOpenGL.cpp b/Engine/Source/Runtime/OpenGLDrv/Private/Android/AndroidOpenGL.cpp index 8c97be4bcff8..13e20a45b8c1 100644 --- a/Engine/Source/Runtime/OpenGLDrv/Private/Android/AndroidOpenGL.cpp +++ b/Engine/Source/Runtime/OpenGLDrv/Private/Android/AndroidOpenGL.cpp @@ -71,14 +71,6 @@ PFNGLCLEARBUFFERUIVPROC glClearBufferuiv = NULL; PFNGLDRAWBUFFERSPROC glDrawBuffers = NULL; PFNGLTEXBUFFEREXTPROC glTexBufferEXT = NULL; -static TAutoConsoleVariable CVarAndroidDisableTextureFormatBGRA8888( - TEXT("android.DisableTextureFormatBGRA8888"), - 0, - TEXT("Whether to disable usage of GL_EXT_texture_format_BGRA8888 extension.\n") - TEXT(" 0: Enable when extension is available (default)\n") - TEXT(" 1: Always disabled"), - ECVF_ReadOnly); - struct FPlatformOpenGLDevice { @@ -346,6 +338,7 @@ bool FAndroidOpenGL::bUseES30ShadingLanguage = false; bool FAndroidOpenGL::bES30Support = false; bool FAndroidOpenGL::bES31Support = false; bool FAndroidOpenGL::bSupportsInstancing = false; +bool FAndroidOpenGL::bHasHardwareHiddenSurfaceRemoval = false; void FAndroidOpenGL::ProcessExtensions(const FString& ExtensionsString) { @@ -405,6 +398,13 @@ void FAndroidOpenGL::ProcessExtensions(const FString& ExtensionsString) bRequiresTexture2DPrecisionHack = true; } + const bool bIsPoverVRBased = RendererString.Contains(TEXT("PowerVR")); + if (bIsPoverVRBased) + { + bHasHardwareHiddenSurfaceRemoval = true; + UE_LOG(LogRHI, Log, TEXT("Enabling support for Hidden Surface Removal on PowerVR")); + } + const bool bIsAdrenoBased = RendererString.Contains(TEXT("Adreno")); if (bIsAdrenoBased) { @@ -495,10 +495,22 @@ void FAndroidOpenGL::ProcessExtensions(const FString& ExtensionsString) bSupportsInstancing = false; } - if (bSupportsBGRA8888 && CVarAndroidDisableTextureFormatBGRA8888.GetValueOnAnyThread() == 1) + if (bSupportsBGRA8888) { - UE_LOG(LogRHI, Warning, TEXT("Disabling support for GL_EXT_texture_format_BGRA8888")); - bSupportsBGRA8888 = false; + // Check whether device supports BGRA as color attachment + GLuint FrameBuffer; + glGenFramebuffers(1, &FrameBuffer); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, FrameBuffer); + GLuint BGRA8888Texture; + glGenTextures(1, &BGRA8888Texture); + glBindTexture(GL_TEXTURE_2D, BGRA8888Texture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA_EXT, 256, 256, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, NULL); + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, BGRA8888Texture, 0); + + bSupportsBGRA8888RenderTarget = (glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); + + glDeleteTextures(1, &BGRA8888Texture); + glDeleteFramebuffers(1, &FrameBuffer); } } diff --git a/Engine/Source/Runtime/OpenGLDrv/Private/Android/AndroidOpenGL.h b/Engine/Source/Runtime/OpenGLDrv/Private/Android/AndroidOpenGL.h index 163170f8b789..a677a64f637f 100644 --- a/Engine/Source/Runtime/OpenGLDrv/Private/Android/AndroidOpenGL.h +++ b/Engine/Source/Runtime/OpenGLDrv/Private/Android/AndroidOpenGL.h @@ -147,6 +147,8 @@ struct FAndroidOpenGL : public FOpenGLES2 return SP_OPENGL_ES2_ANDROID; } + static FORCEINLINE bool HasHardwareHiddenSurfaceRemoval() { return bHasHardwareHiddenSurfaceRemoval; }; + // Optional: static FORCEINLINE void QueryTimestampCounter(GLuint QueryID) { @@ -386,6 +388,9 @@ struct FAndroidOpenGL : public FOpenGLES2 // whether device supports hardware instancing static bool bSupportsInstancing; + + /** Whether device supports Hidden Surface Removal */ + static bool bHasHardwareHiddenSurfaceRemoval; }; typedef FAndroidOpenGL FOpenGL; diff --git a/Engine/Source/Runtime/OpenGLDrv/Private/HTML5/HTML5OpenGL.cpp b/Engine/Source/Runtime/OpenGLDrv/Private/HTML5/HTML5OpenGL.cpp index b67f9c6c9e86..833c52d2dd8a 100644 --- a/Engine/Source/Runtime/OpenGLDrv/Private/HTML5/HTML5OpenGL.cpp +++ b/Engine/Source/Runtime/OpenGLDrv/Private/HTML5/HTML5OpenGL.cpp @@ -50,6 +50,7 @@ void FHTML5OpenGL::ProcessExtensions( const FString& ExtensionsString ) bSupportsRGBA8 = false; // This is not color-renderable in WebGL/ANGLE (ANGLE exposes this) bSupportsBGRA8888 = false; + bSupportsBGRA8888RenderTarget = false; // ANGLE/WEBGL_depth_texture is sort of like OES_depth_texture, you just can't upload bulk data to it (via Tex*Image2D); that should be OK? bSupportsDepthTexture = ExtensionsString.Contains(TEXT("WEBGL_depth_texture")) || // Catch "WEBGL_depth_texture", "MOZ_WEBGL_depth_texture" and "WEBKIT_WEBGL_depth_texture". diff --git a/Engine/Source/Runtime/OpenGLDrv/Private/OpenGLCommands.cpp b/Engine/Source/Runtime/OpenGLDrv/Private/OpenGLCommands.cpp index 8f33ff9db0b4..c852b2beda47 100644 --- a/Engine/Source/Runtime/OpenGLDrv/Private/OpenGLCommands.cpp +++ b/Engine/Source/Runtime/OpenGLDrv/Private/OpenGLCommands.cpp @@ -2806,7 +2806,7 @@ void FOpenGLDynamicRHI::RHIDrawIndexedPrimitive(FIndexBufferRHIParamRef IndexBuf VerifyProgramPipeline(); #endif - // @todo Workaround for radr://15076670 "Incorrect gl_VertexID in GLSL for glDrawElementsInstanced without vertex streams on Nvidia” Alternative fix that avoids exposing the messy details to the Renderer, keeping it here in the RHI. + // @todo Workaround for radr://15076670 "Incorrect gl_VertexID in GLSL for glDrawElementsInstanced without vertex streams on Nvidia" Alternative fix that avoids exposing the messy details to the Renderer, keeping it here in the RHI. // This workaround has performance and correctness implications - it is only needed on Mac + OpenGL + Nvidia and will // break AMD drivers entirely as it is technically an abuse of the OpenGL specification. Consequently it is deliberately // compiled out for other platforms. Apple have closed the bug claiming the NV behaviour is permitted by the GL spec. @@ -2855,7 +2855,7 @@ void FOpenGLDynamicRHI::RHIDrawIndexedPrimitive(FIndexBufferRHIParamRef IndexBuf REPORT_GL_DRAW_RANGE_ELEMENTS_EVENT_FOR_FRAME_DUMP(DrawMode, MinIndex, MinIndex + NumVertices, NumElements, IndexType, (void *)StartIndex); } - // @todo Workaround for radr://15076670 "Incorrect gl_VertexID in GLSL for glDrawElementsInstanced without vertex streams on Nvidia” + // @todo Workaround for radr://15076670 "Incorrect gl_VertexID in GLSL for glDrawElementsInstanced without vertex streams on Nvidia" #if PLATFORM_MAC if(bAttributeLessDraw) { diff --git a/Engine/Source/Runtime/OpenGLDrv/Private/OpenGLDevice.cpp b/Engine/Source/Runtime/OpenGLDrv/Private/OpenGLDevice.cpp index edb29ee286e4..8b13dd2b4d14 100644 --- a/Engine/Source/Runtime/OpenGLDrv/Private/OpenGLDevice.cpp +++ b/Engine/Source/Runtime/OpenGLDrv/Private/OpenGLDevice.cpp @@ -480,8 +480,17 @@ void InitDebugContext() #endif } -TAutoConsoleVariable CVarOpenGLStripExtensions(TEXT("r.OpenGL.StripExtensions"), TEXT(""), TEXT("List of comma separated OpenGL extensions to remove from driver reported extensions string")); -TAutoConsoleVariable CVarOpenGLAddExtensions(TEXT("r.OpenGL.AddExtensions"), TEXT(""), TEXT("List of comma separated OpenGL extensions to driver reported extensions string")); +TAutoConsoleVariable CVarOpenGLStripExtensions( + TEXT("r.OpenGL.StripExtensions"), + TEXT(""), + TEXT("List of comma separated OpenGL extensions to strip from a driver reported extensions string"), + ECVF_ReadOnly); + +TAutoConsoleVariable CVarOpenGLAddExtensions( + TEXT("r.OpenGL.AddExtensions"), + TEXT(""), + TEXT("List of comma separated OpenGL extensions to add to a driver reported extensions string"), + ECVF_ReadOnly); void ApplyExtensionsOverrides(FString& ExtensionsString) { diff --git a/Engine/Source/Runtime/OpenGLDrv/Private/OpenGLES2.cpp b/Engine/Source/Runtime/OpenGLDrv/Private/OpenGLES2.cpp index fd41511e0602..e06788dd7326 100644 --- a/Engine/Source/Runtime/OpenGLDrv/Private/OpenGLES2.cpp +++ b/Engine/Source/Runtime/OpenGLDrv/Private/OpenGLES2.cpp @@ -40,6 +40,9 @@ bool FOpenGLES2::bSupportsRGBA8 = false; /** GL_APPLE_texture_format_BGRA8888 */ bool FOpenGLES2::bSupportsBGRA8888 = false; +/** Whether BGRA supported as color attachment */ +bool FOpenGLES2::bSupportsBGRA8888RenderTarget = false; + /** GL_EXT_discard_framebuffer */ bool FOpenGLES2::bSupportsDiscardFrameBuffer = false; @@ -205,6 +208,7 @@ void FOpenGLES2::ProcessExtensions( const FString& ExtensionsString ) bTimerQueryCanBeDisjoint = !ExtensionsString.Contains(TEXT("GL_NV_timer_query")); bSupportsRGBA8 = ExtensionsString.Contains(TEXT("GL_OES_rgb8_rgba8")); bSupportsBGRA8888 = ExtensionsString.Contains(TEXT("GL_APPLE_texture_format_BGRA8888")) || ExtensionsString.Contains(TEXT("GL_IMG_texture_format_BGRA8888")) || ExtensionsString.Contains(TEXT("GL_EXT_texture_format_BGRA8888")); + bSupportsBGRA8888RenderTarget = bSupportsBGRA8888; bSupportsVertexHalfFloat = ExtensionsString.Contains(TEXT("GL_OES_vertex_half_float")); bSupportsTextureFloat = ExtensionsString.Contains(TEXT("GL_OES_texture_float")); bSupportsTextureHalfFloat = ExtensionsString.Contains(TEXT("GL_OES_texture_half_float")); diff --git a/Engine/Source/Runtime/OpenGLDrv/Private/OpenGLES31.cpp b/Engine/Source/Runtime/OpenGLDrv/Private/OpenGLES31.cpp index dddf79e8475f..2da4c0f71fd2 100644 --- a/Engine/Source/Runtime/OpenGLDrv/Private/OpenGLES31.cpp +++ b/Engine/Source/Runtime/OpenGLDrv/Private/OpenGLES31.cpp @@ -49,6 +49,9 @@ bool FOpenGLES31::bSupportsRGBA8 = false; /** GL_APPLE_texture_format_BGRA8888 */ bool FOpenGLES31::bSupportsBGRA8888 = false; +/** Whether BGRA supported as color attachment */ +bool FOpenGLES31::bSupportsBGRA8888RenderTarget = false; + /** GL_EXT_discard_framebuffer */ bool FOpenGLES31::bSupportsDiscardFrameBuffer = false; @@ -345,6 +348,24 @@ void FOpenGLES31::ProcessExtensions( const FString& ExtensionsString ) glDeleteFramebuffers(1, &FrameBuffer); } + if (bSupportsBGRA8888) + { + // Check whether device supports BGRA as color attachment + GLuint FrameBuffer; + glGenFramebuffers(1, &FrameBuffer); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, FrameBuffer); + GLuint BGRA8888Texture; + glGenTextures(1, &BGRA8888Texture); + glBindTexture(GL_TEXTURE_2D, BGRA8888Texture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA_EXT, 256, 256, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, NULL); + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, BGRA8888Texture, 0); + + bSupportsBGRA8888RenderTarget = (glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); + + glDeleteTextures(1, &BGRA8888Texture); + glDeleteFramebuffers(1, &FrameBuffer); + } + bSupportsCopyImage = ExtensionsString.Contains(TEXT("GL_EXT_copy_image")); } diff --git a/Engine/Source/Runtime/OpenGLDrv/Private/OpenGLTexture.cpp b/Engine/Source/Runtime/OpenGLDrv/Private/OpenGLTexture.cpp index 79251b11c4a3..64fc6e80293b 100644 --- a/Engine/Source/Runtime/OpenGLDrv/Private/OpenGLTexture.cpp +++ b/Engine/Source/Runtime/OpenGLDrv/Private/OpenGLTexture.cpp @@ -256,8 +256,14 @@ FRHITexture* FOpenGLDynamicRHI::CreateOpenGLTexture(uint32 SizeX, uint32 SizeY, check( bArrayTexture != (ArraySize == 1)); #endif - bool bNoSRGBSupport = (GMaxRHIFeatureLevel <= ERHIFeatureLevel::ES2); - + bool bNoSRGBSupport = (GMaxRHIFeatureLevel <= ERHIFeatureLevel::ES3_1); + + if ((Flags & TexCreate_RenderTargetable) && Format == PF_B8G8R8A8 && !FOpenGL::SupportsBGRA8888RenderTarget()) + { + // Some android devices does not support BGRA as a color attachment + Format = PF_R8G8B8A8; + } + if (bNoSRGBSupport) { // Remove sRGB read flag when not supported @@ -1468,7 +1474,7 @@ FTexture2DArrayRHIRef FOpenGLDynamicRHI::RHICreateTexture2DArray(uint32 SizeX,ui NumMips = FindMaxMipmapLevel(SizeX, SizeY); } - if (GMaxRHIFeatureLevel <= ERHIFeatureLevel::ES2) + if (GMaxRHIFeatureLevel <= ERHIFeatureLevel::ES3_1) { // Remove sRGB read flag when not supported Flags &= ~TexCreate_SRGB; @@ -1579,7 +1585,7 @@ FTexture3DRHIRef FOpenGLDynamicRHI::RHICreateTexture3D(uint32 SizeX,uint32 SizeY NumMips = FindMaxMipmapLevel(SizeX, SizeY, SizeZ); } - if (GMaxRHIFeatureLevel <= ERHIFeatureLevel::ES2) + if (GMaxRHIFeatureLevel <= ERHIFeatureLevel::ES3_1) { // Remove sRGB read flag when not supported Flags &= ~TexCreate_SRGB; diff --git a/Engine/Source/Runtime/OpenGLDrv/Public/OpenGL.h b/Engine/Source/Runtime/OpenGLDrv/Public/OpenGL.h index 398c26a6c6cc..c4890abc0875 100644 --- a/Engine/Source/Runtime/OpenGLDrv/Public/OpenGL.h +++ b/Engine/Source/Runtime/OpenGLDrv/Public/OpenGL.h @@ -116,6 +116,7 @@ public: static FORCEINLINE bool SupportsShaderDepthStencilFetch() { return false; } static FORCEINLINE bool SupportsVertexArrayBGRA() { return true; } static FORCEINLINE bool SupportsBGRA8888() { return true; } + static FORCEINLINE bool SupportsBGRA8888RenderTarget() { return true; } static FORCEINLINE bool SupportsSRGB() { return true; } static FORCEINLINE bool SupportsRGBA8() { return true; } static FORCEINLINE bool SupportsDXT() { return true; } diff --git a/Engine/Source/Runtime/OpenGLDrv/Public/OpenGLES2.h b/Engine/Source/Runtime/OpenGLDrv/Public/OpenGLES2.h index 4b77ad567d81..48a92acc9b1c 100644 --- a/Engine/Source/Runtime/OpenGLDrv/Public/OpenGLES2.h +++ b/Engine/Source/Runtime/OpenGLDrv/Public/OpenGLES2.h @@ -117,6 +117,7 @@ struct FOpenGLES2 : public FOpenGLBase static FORCEINLINE bool SupportsMultisampledRenderToTexture() { return bSupportsMultisampledRenderToTexture; } static FORCEINLINE bool SupportsVertexArrayBGRA() { return false; } static FORCEINLINE bool SupportsBGRA8888() { return bSupportsBGRA8888; } + static FORCEINLINE bool SupportsBGRA8888RenderTarget() { return bSupportsBGRA8888RenderTarget; } static FORCEINLINE bool SupportsSRGB() { return bSupportsSGRB; } static FORCEINLINE bool SupportsRGBA8() { return bSupportsRGBA8; } static FORCEINLINE bool SupportsDXT() { return bSupportsDXT; } @@ -409,6 +410,9 @@ protected: /** GL_APPLE_texture_format_BGRA8888 */ static bool bSupportsBGRA8888; + /** Whether BGRA supported as color attachment */ + static bool bSupportsBGRA8888RenderTarget; + /** GL_OES_vertex_half_float */ static bool bSupportsVertexHalfFloat; diff --git a/Engine/Source/Runtime/OpenGLDrv/Public/OpenGLES31.h b/Engine/Source/Runtime/OpenGLDrv/Public/OpenGLES31.h index 7bb1f7d4eae7..46034ad56d94 100644 --- a/Engine/Source/Runtime/OpenGLDrv/Public/OpenGLES31.h +++ b/Engine/Source/Runtime/OpenGLDrv/Public/OpenGLES31.h @@ -76,6 +76,7 @@ struct FOpenGLES31 : public FOpenGLBase static FORCEINLINE bool SupportsMultisampledRenderToTexture() { return bSupportsMultisampledRenderToTexture; } static FORCEINLINE bool SupportsVertexArrayBGRA() { return false; } static FORCEINLINE bool SupportsBGRA8888() { return bSupportsBGRA8888; } + static FORCEINLINE bool SupportsBGRA8888RenderTarget() { return bSupportsBGRA8888RenderTarget; } static FORCEINLINE bool SupportsSRGB() { return bSupportsSGRB || !bES2Fallback; } static FORCEINLINE bool SupportsRGBA8() { return bSupportsRGBA8; } static FORCEINLINE bool SupportsDXT() { return bSupportsDXT; } @@ -862,6 +863,9 @@ protected: /** GL_APPLE_texture_format_BGRA8888 */ static bool bSupportsBGRA8888; + /** Whether BGRA supported as color attachment */ + static bool bSupportsBGRA8888RenderTarget; + /** GL_OES_vertex_half_float */ static bool bSupportsVertexHalfFloat; diff --git a/Engine/Source/Runtime/RHI/Private/RHI.cpp b/Engine/Source/Runtime/RHI/Private/RHI.cpp index eec54322cee0..632671189e35 100644 --- a/Engine/Source/Runtime/RHI/Private/RHI.cpp +++ b/Engine/Source/Runtime/RHI/Private/RHI.cpp @@ -384,6 +384,7 @@ static FName NAME_VULKAN_SM4(TEXT("SF_VULKAN_SM4")); static FName NAME_VULKAN_SM5(TEXT("SF_VULKAN_SM5")); static FName NAME_SF_METAL_SM4(TEXT("SF_METAL_SM4")); static FName NAME_SF_METAL_MACES3_1(TEXT("SF_METAL_MACES3_1")); +static FName NAME_SF_METAL_MACES2(TEXT("SF_METAL_MACES2")); FName LegacyShaderPlatformToShaderFormat(EShaderPlatform Platform) { @@ -430,6 +431,8 @@ FName LegacyShaderPlatformToShaderFormat(EShaderPlatform Platform) return NAME_SF_METAL_SM5; case SP_METAL_MACES3_1: return NAME_SF_METAL_MACES3_1; + case SP_METAL_MACES2: + return NAME_SF_METAL_MACES2; case SP_OPENGL_ES31_EXT: return NAME_GLSL_310_ES_EXT; case SP_VULKAN_SM4: @@ -474,10 +477,11 @@ EShaderPlatform ShaderFormatToLegacyShaderPlatform(FName ShaderFormat) if (ShaderFormat == NAME_VULKAN_SM4) return SP_VULKAN_SM4; if (ShaderFormat == NAME_VULKAN_SM5) return SP_VULKAN_SM5; if (ShaderFormat == NAME_VULKAN_ES3_1_ANDROID) return SP_VULKAN_ES3_1_ANDROID; - if (ShaderFormat == NAME_VULKAN_ES3_1) return SP_VULKAN_ES3_1_ANDROID; - if (ShaderFormat == NAME_VULKAN_ES3_1_UB) return SP_VULKAN_ES3_1_ANDROID; + if (ShaderFormat == NAME_VULKAN_ES3_1) return SP_VULKAN_PCES3_1; + if (ShaderFormat == NAME_VULKAN_ES3_1_UB) return SP_VULKAN_PCES3_1; if (ShaderFormat == NAME_SF_METAL_SM4) return SP_METAL_SM4; if (ShaderFormat == NAME_SF_METAL_MACES3_1) return SP_METAL_MACES3_1; + if (ShaderFormat == NAME_SF_METAL_MACES2) return SP_METAL_MACES2; return SP_NumPlatforms; } diff --git a/Engine/Source/Runtime/RHI/Public/RHIDefinitions.h b/Engine/Source/Runtime/RHI/Public/RHIDefinitions.h index f41a72598b89..1490066c0977 100644 --- a/Engine/Source/Runtime/RHI/Public/RHIDefinitions.h +++ b/Engine/Source/Runtime/RHI/Public/RHIDefinitions.h @@ -11,53 +11,54 @@ enum EShaderFrequency { - SF_Vertex = 0, - SF_Hull = 1, - SF_Domain = 2, - SF_Pixel = 3, - SF_Geometry = 4, - SF_Compute = 5, + SF_Vertex = 0, + SF_Hull = 1, + SF_Domain = 2, + SF_Pixel = 3, + SF_Geometry = 4, + SF_Compute = 5, - SF_NumFrequencies = 6, + SF_NumFrequencies = 6, - SF_NumBits = 3, + SF_NumBits = 3, }; static_assert(SF_NumFrequencies <= (1 << SF_NumBits), "SF_NumFrequencies will not fit on SF_NumBits"); /** @warning: update *LegacyShaderPlatform* when the below changes */ enum EShaderPlatform { - SP_PCD3D_SM5 = 0, - SP_OPENGL_SM4 = 1, - SP_PS4 = 2, + SP_PCD3D_SM5 = 0, + SP_OPENGL_SM4 = 1, + SP_PS4 = 2, /** Used when running in Feature Level ES2 in OpenGL. */ - SP_OPENGL_PCES2 = 3, - SP_XBOXONE = 4, - SP_PCD3D_SM4 = 5, - SP_OPENGL_SM5 = 6, + SP_OPENGL_PCES2 = 3, + SP_XBOXONE = 4, + SP_PCD3D_SM4 = 5, + SP_OPENGL_SM5 = 6, /** Used when running in Feature Level ES2 in D3D11. */ - SP_PCD3D_ES2 = 7, + SP_PCD3D_ES2 = 7, SP_OPENGL_ES2_ANDROID = 8, - SP_OPENGL_ES2_WEBGL = 9, - SP_OPENGL_ES2_IOS = 10, - SP_METAL = 11, - SP_OPENGL_SM4_MAC = 12, - SP_METAL_MRT = 13, - SP_OPENGL_ES31_EXT = 14, + SP_OPENGL_ES2_WEBGL = 9, + SP_OPENGL_ES2_IOS = 10, + SP_METAL = 11, + SP_OPENGL_SM4_MAC = 12, + SP_METAL_MRT = 13, + SP_OPENGL_ES31_EXT = 14, /** Used when running in Feature Level ES3_1 in D3D11. */ - SP_PCD3D_ES3_1 = 15, + SP_PCD3D_ES3_1 = 15, /** Used when running in Feature Level ES3_1 in OpenGL. */ - SP_OPENGL_PCES3_1 = 16, - SP_METAL_SM5 = 17, - SP_VULKAN_PCES3_1 = 18, - SP_METAL_SM4 = 19, - SP_VULKAN_SM4 = 20, - SP_VULKAN_SM5 = 21, + SP_OPENGL_PCES3_1 = 16, + SP_METAL_SM5 = 17, + SP_VULKAN_PCES3_1 = 18, + SP_METAL_SM4 = 19, + SP_VULKAN_SM4 = 20, + SP_VULKAN_SM5 = 21, SP_VULKAN_ES3_1_ANDROID = 22, - SP_METAL_MACES3_1 = 23, + SP_METAL_MACES3_1 = 23, + SP_METAL_MACES2 = 24, - SP_NumPlatforms = 24, - SP_NumBits = 5, + SP_NumPlatforms = 25, + SP_NumBits = 5, }; static_assert(SP_NumPlatforms <= (1 << SP_NumBits), "SP_NumPlatforms will not fit on SP_NumBits"); @@ -159,16 +160,16 @@ enum ERasterizerCullMode enum EColorWriteMask { - CW_RED = 0x01, + CW_RED = 0x01, CW_GREEN = 0x02, - CW_BLUE = 0x04, + CW_BLUE = 0x04, CW_ALPHA = 0x08, - CW_NONE = 0, - CW_RGB = CW_RED | CW_GREEN | CW_BLUE, - CW_RGBA = CW_RED | CW_GREEN | CW_BLUE | CW_ALPHA, - CW_RG = CW_RED | CW_GREEN, - CW_BA = CW_BLUE | CW_ALPHA, + CW_NONE = 0, + CW_RGB = CW_RED | CW_GREEN | CW_BLUE, + CW_RGBA = CW_RED | CW_GREEN | CW_BLUE | CW_ALPHA, + CW_RG = CW_RED | CW_GREEN, + CW_BA = CW_BLUE | CW_ALPHA, }; enum ECompareFunction @@ -183,10 +184,10 @@ enum ECompareFunction CF_Always, // Utility enumerations - CF_DepthNearOrEqual = (((int32)ERHIZBuffer::IsInverted != 0) ? CF_GreaterEqual : CF_LessEqual), - CF_DepthNear = (((int32)ERHIZBuffer::IsInverted != 0) ? CF_Greater : CF_Less), - CF_DepthFartherOrEqual = (((int32)ERHIZBuffer::IsInverted != 0) ? CF_LessEqual : CF_GreaterEqual), - CF_DepthFarther = (((int32)ERHIZBuffer::IsInverted != 0) ? CF_Less : CF_Greater), + CF_DepthNearOrEqual = (((int32)ERHIZBuffer::IsInverted != 0) ? CF_GreaterEqual : CF_LessEqual), + CF_DepthNear = (((int32)ERHIZBuffer::IsInverted != 0) ? CF_Greater : CF_Less), + CF_DepthFartherOrEqual = (((int32)ERHIZBuffer::IsInverted != 0) ? CF_LessEqual : CF_GreaterEqual), + CF_DepthFarther = (((int32)ERHIZBuffer::IsInverted != 0) ? CF_Less : CF_Greater), }; enum EStencilOp @@ -320,17 +321,17 @@ public: private: enum EResourceTableDefinitions { - RTD_NumBits_UniformBufferIndex = 8, - RTD_NumBits_ResourceIndex = 16, - RTD_NumBits_BindIndex = 8, + RTD_NumBits_UniformBufferIndex = 8, + RTD_NumBits_ResourceIndex = 16, + RTD_NumBits_BindIndex = 8, - RTD_Mask_UniformBufferIndex = (1 << RTD_NumBits_UniformBufferIndex) - 1, - RTD_Mask_ResourceIndex = (1 << RTD_NumBits_ResourceIndex) - 1, - RTD_Mask_BindIndex = (1 << RTD_NumBits_BindIndex) - 1, + RTD_Mask_UniformBufferIndex = (1 << RTD_NumBits_UniformBufferIndex) - 1, + RTD_Mask_ResourceIndex = (1 << RTD_NumBits_ResourceIndex) - 1, + RTD_Mask_BindIndex = (1 << RTD_NumBits_BindIndex) - 1, - RTD_Shift_BindIndex = 0, - RTD_Shift_ResourceIndex = RTD_Shift_BindIndex + RTD_NumBits_BindIndex, - RTD_Shift_UniformBufferIndex = RTD_Shift_ResourceIndex + RTD_NumBits_ResourceIndex, + RTD_Shift_BindIndex = 0, + RTD_Shift_ResourceIndex = RTD_Shift_BindIndex + RTD_NumBits_BindIndex, + RTD_Shift_UniformBufferIndex = RTD_Shift_ResourceIndex + RTD_NumBits_ResourceIndex, }; static_assert(RTD_NumBits_UniformBufferIndex + RTD_NumBits_ResourceIndex + RTD_NumBits_BindIndex <= sizeof(uint32)* 8, "RTD_* values must fit in 32 bits"); }; @@ -407,41 +408,41 @@ static_assert(PT_Num <= (1 << PT_NumBits), "PT_NumBits is too small"); enum EBufferUsageFlags { // Mutually exclusive write-frequency flags - BUF_Static = 0x0001, // The buffer will be written to once. + BUF_Static = 0x0001, // The buffer will be written to once. BUF_Dynamic = 0x0002, // The buffer will be written to occasionally, GPU read only, CPU write only. The data lifetime is until the next update, or the buffer is destroyed. - BUF_Volatile = 0x0004, // The buffer's data will have a lifetime of one frame. It MUST be written to each frame, or a new one created each frame. + BUF_Volatile = 0x0004, // The buffer's data will have a lifetime of one frame. It MUST be written to each frame, or a new one created each frame. // Mutually exclusive bind flags. - BUF_UnorderedAccess = 0x0008, // Allows an unordered access view to be created for the buffer. + BUF_UnorderedAccess = 0x0008, // Allows an unordered access view to be created for the buffer. /** Create a byte address buffer, which is basically a structured buffer with a uint32 type. */ BUF_ByteAddressBuffer = 0x0020, /** Create a structured buffer with an atomic UAV counter. */ - BUF_UAVCounter = 0x0040, + BUF_UAVCounter = 0x0040, /** Create a buffer that can be bound as a stream output target. */ - BUF_StreamOutput = 0x0080, + BUF_StreamOutput = 0x0080, /** Create a buffer which contains the arguments used by DispatchIndirect or DrawIndirect. */ - BUF_DrawIndirect = 0x0100, - /** - * Create a buffer that can be bound as a shader resource. - * This is only needed for buffer types which wouldn't ordinarily be used as a shader resource, like a vertex buffer. - */ - BUF_ShaderResource = 0x0200, + BUF_DrawIndirect = 0x0100, + /** + * Create a buffer that can be bound as a shader resource. + * This is only needed for buffer types which wouldn't ordinarily be used as a shader resource, like a vertex buffer. + */ + BUF_ShaderResource = 0x0200, /** - * Request that this buffer is directly CPU accessible - * (@todo josh: this is probably temporary and will go away in a few months) - */ + * Request that this buffer is directly CPU accessible + * (@todo josh: this is probably temporary and will go away in a few months) + */ BUF_KeepCPUAccessible = 0x0400, /** - * Provide information that this buffer will contain only one vertex, which should be delivered to every primitive drawn. - * This is necessary for OpenGL implementations, which need to handle this case very differently (and can't handle GL_HALF_FLOAT in such vertices at all). - */ - BUF_ZeroStride = 0x0800, + * Provide information that this buffer will contain only one vertex, which should be delivered to every primitive drawn. + * This is necessary for OpenGL implementations, which need to handle this case very differently (and can't handle GL_HALF_FLOAT in such vertices at all). + */ + BUF_ZeroStride = 0x0800, /** Buffer should go in fast vram (hint only) */ - BUF_FastVRAM = 0x1000, + BUF_FastVRAM = 0x1000, // Helper bit-masks BUF_AnyDynamic = (BUF_Dynamic | BUF_Volatile), @@ -485,7 +486,7 @@ enum ERHIResourceType /** Flags used for texture creation */ enum ETextureCreateFlags { - TexCreate_None = 0, + TexCreate_None = 0, // Texture can be used as a render target TexCreate_RenderTargetable = 1<<0, @@ -541,6 +542,8 @@ enum ETextureCreateFlags TexCreate_NoFastClear = 1 << 25, // Texture is a depth stencil resolve target TexCreate_DepthStencilResolveTarget = 1 << 26, + // RenderTarget will create with delta color compression + TexCreate_DeltaColorCompression = 1 << 27, }; enum EAsyncComputePriority @@ -612,13 +615,13 @@ inline bool IsPCPlatform(const EShaderPlatform Platform) return Platform == SP_PCD3D_SM5 || Platform == SP_PCD3D_SM4 || Platform == SP_PCD3D_ES2 || Platform == SP_PCD3D_ES3_1 || Platform == SP_OPENGL_SM4 || Platform == SP_OPENGL_SM4_MAC || Platform == SP_OPENGL_SM5 || Platform == SP_OPENGL_PCES2 || Platform == SP_OPENGL_PCES3_1 || Platform == SP_METAL_SM4 || Platform == SP_METAL_SM5 || - Platform == SP_VULKAN_PCES3_1 || Platform == SP_VULKAN_SM4 || Platform == SP_VULKAN_SM5 || Platform == SP_METAL_MACES3_1; + Platform == SP_VULKAN_PCES3_1 || Platform == SP_VULKAN_SM4 || Platform == SP_VULKAN_SM5 || Platform == SP_METAL_MACES3_1 || Platform == SP_METAL_MACES2; } /** Whether the shader platform corresponds to the ES2 feature level. */ inline bool IsES2Platform(const EShaderPlatform Platform) { - return Platform == SP_PCD3D_ES2 || Platform == SP_OPENGL_PCES2 || Platform == SP_OPENGL_ES2_ANDROID || Platform == SP_OPENGL_ES2_WEBGL || Platform == SP_OPENGL_ES2_IOS || Platform == SP_METAL; + return Platform == SP_PCD3D_ES2 || Platform == SP_OPENGL_PCES2 || Platform == SP_OPENGL_ES2_ANDROID || Platform == SP_OPENGL_ES2_WEBGL || Platform == SP_OPENGL_ES2_IOS || Platform == SP_METAL_MACES2; } /** Whether the shader platform corresponds to the ES2/ES3.1 feature level. */ @@ -635,7 +638,7 @@ inline bool IsOpenGLPlatform(const EShaderPlatform Platform) inline bool IsMetalPlatform(const EShaderPlatform Platform) { - return Platform == SP_METAL || Platform == SP_METAL_MRT || Platform == SP_METAL_SM4 || Platform == SP_METAL_SM5 || Platform == SP_METAL_MACES3_1; + return Platform == SP_METAL || Platform == SP_METAL_MRT || Platform == SP_METAL_SM4 || Platform == SP_METAL_SM5 || Platform == SP_METAL_MACES3_1 || Platform == SP_METAL_MACES2; } inline bool IsConsolePlatform(const EShaderPlatform Platform) @@ -677,6 +680,7 @@ inline ERHIFeatureLevel::Type GetMaxSupportedFeatureLevel(EShaderPlatform InShad case SP_OPENGL_ES2_ANDROID: case SP_OPENGL_ES2_WEBGL: case SP_OPENGL_ES2_IOS: + case SP_METAL_MACES2: return ERHIFeatureLevel::ES2; case SP_METAL: case SP_METAL_MACES3_1: @@ -741,6 +745,8 @@ inline bool IsFeatureLevelSupported(EShaderPlatform InShaderPlatform, ERHIFeatur return InFeatureLevel <= ERHIFeatureLevel::SM5; case SP_METAL_MACES3_1: return InFeatureLevel <= ERHIFeatureLevel::ES3_1; + case SP_METAL_MACES2: + return InFeatureLevel <= ERHIFeatureLevel::ES2; default: return false; } diff --git a/Engine/Source/Runtime/Renderer/Private/BasePassRendering.cpp b/Engine/Source/Runtime/Renderer/Private/BasePassRendering.cpp index 99323f0748f4..c032aac01a2b 100644 --- a/Engine/Source/Runtime/Renderer/Private/BasePassRendering.cpp +++ b/Engine/Source/Runtime/Renderer/Private/BasePassRendering.cpp @@ -143,10 +143,23 @@ void FBasePassReflectionParameters::SetMesh(FRHICommandList& RHICmdList, FPixelS // Note: GBlackCubeArrayTexture has an alpha of 0, which is needed to represent invalid data so the sky cubemap can still be applied FTextureRHIParamRef CubeArrayTexture = FeatureLevel >= ERHIFeatureLevel::SM5 ? GBlackCubeArrayTexture->TextureRHI : GBlackTextureCube->TextureRHI; int32 ArrayIndex = 0; + const FReflectionCaptureProxy* ReflectionProxy = PrimitiveSceneInfo ? PrimitiveSceneInfo->CachedReflectionCaptureProxy : nullptr; - if (PrimitiveSceneInfo && PrimitiveSceneInfo->CachedReflectionCaptureProxy) + FMatrix BoxTransformVal = FMatrix::Identity; + FVector4 PositionAndRadius = FVector::ZeroVector; + FVector4 BoxScalesVal = FVector::ZeroVector; + FVector CaptureOffsetVal = FVector::ZeroVector; + EReflectionCaptureShape::Type CaptureShape = EReflectionCaptureShape::Box; + + + if (PrimitiveSceneInfo && ReflectionProxy) { - PrimitiveSceneInfo->Scene->GetCaptureParameters(PrimitiveSceneInfo->CachedReflectionCaptureProxy, CubeArrayTexture, ArrayIndex); + PrimitiveSceneInfo->Scene->GetCaptureParameters(ReflectionProxy, CubeArrayTexture, ArrayIndex); + PositionAndRadius = FVector4(ReflectionProxy->Position, ReflectionProxy->InfluenceRadius); + CaptureShape = ReflectionProxy->Shape; + BoxTransformVal = ReflectionProxy->BoxTransform; + BoxScalesVal = ReflectionProxy->BoxScales; + CaptureOffsetVal = ReflectionProxy->CaptureOffset; } SetTextureParameter( @@ -158,6 +171,12 @@ void FBasePassReflectionParameters::SetMesh(FRHICommandList& RHICmdList, FPixelS CubeArrayTexture); SetShaderValue(RHICmdList, PixelShaderRHI, CubemapArrayIndex, ArrayIndex); + SetShaderValue(RHICmdList, PixelShaderRHI, ReflectionPositionAndRadius, PositionAndRadius); + SetShaderValue(RHICmdList, PixelShaderRHI, ReflectionShape, (float)CaptureShape); + SetShaderValue(RHICmdList, PixelShaderRHI, BoxTransform, BoxTransformVal); + SetShaderValue(RHICmdList, PixelShaderRHI, BoxScales, BoxScalesVal); + SetShaderValue(RHICmdList, PixelShaderRHI, CaptureOffset, CaptureOffsetVal); + } void FTranslucentLightingParameters::Set(FRHICommandList& RHICmdList, FPixelShaderRHIParamRef PixelShaderRHI, const FViewInfo* View) diff --git a/Engine/Source/Runtime/Renderer/Private/BasePassRendering.h b/Engine/Source/Runtime/Renderer/Private/BasePassRendering.h index 048c54e3d39d..c04a714c73b8 100644 --- a/Engine/Source/Runtime/Renderer/Private/BasePassRendering.h +++ b/Engine/Source/Runtime/Renderer/Private/BasePassRendering.h @@ -400,6 +400,11 @@ public: ReflectionCubemap.Bind(ParameterMap, TEXT("ReflectionCubemap")); ReflectionCubemapSampler.Bind(ParameterMap, TEXT("ReflectionCubemapSampler")); CubemapArrayIndex.Bind(ParameterMap, TEXT("CubemapArrayIndex")); + ReflectionPositionAndRadius.Bind(ParameterMap, TEXT("ReflectionPositionAndRadius")); + ReflectionShape.Bind(ParameterMap, TEXT("ReflectionShape")); + BoxTransform.Bind(ParameterMap, TEXT("BoxTransform")); + BoxScales.Bind(ParameterMap, TEXT("BoxScales")); + CaptureOffset.Bind(ParameterMap, TEXT("CaptureOffset")); SkyLightReflectionParameters.Bind(ParameterMap); } @@ -414,6 +419,11 @@ public: Ar << P.ReflectionCubemap; Ar << P.ReflectionCubemapSampler; Ar << P.CubemapArrayIndex; + Ar << P.ReflectionPositionAndRadius; + Ar << P.ReflectionShape; + Ar << P.BoxTransform; + Ar << P.BoxScales; + Ar << P.CaptureOffset; Ar << P.SkyLightReflectionParameters; return Ar; } @@ -423,7 +433,14 @@ private: FPlanarReflectionParameters PlanarReflectionParameters; FShaderResourceParameter ReflectionCubemap; FShaderResourceParameter ReflectionCubemapSampler; + FShaderParameter CubemapArrayIndex; + FShaderParameter ReflectionPositionAndRadius; + FShaderParameter ReflectionShape; + FShaderParameter BoxTransform; + FShaderParameter BoxScales; + FShaderParameter CaptureOffset; + FSkyLightReflectionParameters SkyLightReflectionParameters; }; diff --git a/Engine/Source/Runtime/Renderer/Private/DeferredShadingRenderer.cpp b/Engine/Source/Runtime/Renderer/Private/DeferredShadingRenderer.cpp index a9966b913738..6029ff25bfac 100644 --- a/Engine/Source/Runtime/Renderer/Private/DeferredShadingRenderer.cpp +++ b/Engine/Source/Runtime/Renderer/Private/DeferredShadingRenderer.cpp @@ -66,6 +66,14 @@ static TAutoConsoleVariable CVarVisualizeTexturePool( ECVF_Cheat | ECVF_RenderThreadSafe); #endif +static TAutoConsoleVariable CVarClearCoatNormal( + TEXT("r.ClearCoatNormal"), + 0, + TEXT("0 to disable clear coat normal.\n") + TEXT(" 0: off\n") + TEXT(" 1: on"), + ECVF_ReadOnly); + static TAutoConsoleVariable CVarRHICmdFlushRenderThreadTasksBasePass( TEXT("r.RHICmdFlushRenderThreadTasksBasePass"), 0, diff --git a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessBufferInspector.cpp b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessBufferInspector.cpp index bf37bae0716e..48e58fdb6f90 100644 --- a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessBufferInspector.cpp +++ b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessBufferInspector.cpp @@ -152,6 +152,27 @@ void FRCPassPostProcessBufferInspector::Process(FRenderingCompositePassContext& } } + ////////////////////////////////////////////////////////////////////////// + // SCENE COLOR + const FTexture2DRHIRef &DestinationBufferSceneColor = Scene->PixelInspectorData.RenderTargetBufferSceneColor[PixelInspectorRequest->BufferIndex]->GetRenderTargetTexture(); + if (DestinationBufferSceneColor.IsValid()) + { + const FRenderingCompositeOutputRef* OutputRef0 = GetInput(ePId_Input2); + if (OutputRef0) + { + FRenderingCompositeOutput* Input = OutputRef0->GetOutput(); + if (Input && Input->PooledRenderTarget.IsValid() && Input->PooledRenderTarget->GetRenderTargetItem().ShaderResourceTexture.IsValid()) + { + FTexture2DRHIRef SourceBufferSceneColor = (FRHITexture2D*)(Input->PooledRenderTarget->GetRenderTargetItem().ShaderResourceTexture.GetReference()); + if (DestinationBufferSceneColor->GetFormat() == SourceBufferSceneColor->GetFormat()) + { + FBox2D DestinationBox(FVector2D(0.0f, 0.0f), FVector2D(1.0f, 1.0f)); + RHICmdList.CopySubTextureRegion(SourceBufferSceneColor, DestinationBufferSceneColor, SourceBox, DestinationBox); + } + } + } + } + ////////////////////////////////////////////////////////////////////////// // HDR const FTexture2DRHIRef &DestinationBufferHDR = Scene->PixelInspectorData.RenderTargetBufferHDR[PixelInspectorRequest->BufferIndex]->GetRenderTargetTexture(); diff --git a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessBufferInspector.h b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessBufferInspector.h index ad374aab8534..fbb417925a78 100644 --- a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessBufferInspector.h +++ b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessBufferInspector.h @@ -11,7 +11,7 @@ // derives from TRenderingCompositePassBase // ePId_Input0: SceneColor // ePId_Input1: SeparateTranslucency -class FRCPassPostProcessBufferInspector : public TRenderingCompositePassBase<2, 1> +class FRCPassPostProcessBufferInspector : public TRenderingCompositePassBase<3, 1> { public: diff --git a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessing.cpp b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessing.cpp index 084d7c919798..33cef986d426 100644 --- a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessing.cpp +++ b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessing.cpp @@ -1836,6 +1836,7 @@ void FPostProcessing::Process(FRHICommandListImmediate& RHICmdList, FViewInfo& V FRenderingCompositePass* Node = Context.Graph.RegisterPass(new(FMemStack::Get()) FRCPassPostProcessBufferInspector(RHICmdList)); Node->SetInput(ePId_Input0, Context.FinalOutput); Node->SetInput(ePId_Input1, HDRColor); + Node->SetInput(ePId_Input2, Context.SceneColor); Context.FinalOutput = FRenderingCompositeOutputRef(Node); } #endif //WITH_EDITOR diff --git a/Engine/Source/Runtime/Renderer/Private/PostProcess/SceneRenderTargets.cpp b/Engine/Source/Runtime/Renderer/Private/PostProcess/SceneRenderTargets.cpp index 482837d2c534..7f41d9d9b2ae 100644 --- a/Engine/Source/Runtime/Renderer/Private/PostProcess/SceneRenderTargets.cpp +++ b/Engine/Source/Runtime/Renderer/Private/PostProcess/SceneRenderTargets.cpp @@ -669,7 +669,7 @@ void FSceneRenderTargets::AllocSceneColor(FRHICommandList& RHICmdList) // Create the scene color. { - FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(BufferSize, SceneColorBufferFormat, FClearValueBinding::Black, TexCreate_None, TexCreate_RenderTargetable, false)); + FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(BufferSize, SceneColorBufferFormat, FClearValueBinding::Black, TexCreate_None, TexCreate_RenderTargetable | TexCreate_DeltaColorCompression, false)); Desc.Flags |= TexCreate_FastVRAM; @@ -780,7 +780,7 @@ void FSceneRenderTargets::AllocGBufferTargets(FRHICommandList& RHICmdList) NormalGBufferFormat = PF_FloatRGBA; } - FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(BufferSize, NormalGBufferFormat, FClearValueBinding::Transparent, TexCreate_None, TexCreate_RenderTargetable, false)); + FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(BufferSize, NormalGBufferFormat, FClearValueBinding::Transparent, TexCreate_None, TexCreate_RenderTargetable | TexCreate_DeltaColorCompression, false)); GRenderTargetPool.FindFreeElement(RHICmdList, Desc, GBufferA, TEXT("GBufferA")); } @@ -788,26 +788,26 @@ void FSceneRenderTargets::AllocGBufferTargets(FRHICommandList& RHICmdList) { const EPixelFormat SpecularGBufferFormat = bHighPrecisionGBuffers ? PF_FloatRGBA : PF_B8G8R8A8; - FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(BufferSize, SpecularGBufferFormat, FClearValueBinding::Transparent, TexCreate_None, TexCreate_RenderTargetable, false)); + FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(BufferSize, SpecularGBufferFormat, FClearValueBinding::Transparent, TexCreate_None, TexCreate_RenderTargetable | TexCreate_DeltaColorCompression, false)); GRenderTargetPool.FindFreeElement(RHICmdList, Desc, GBufferB, TEXT("GBufferB")); } // Create the diffuse color g-buffer. { const EPixelFormat DiffuseGBufferFormat = bHighPrecisionGBuffers ? PF_FloatRGBA : PF_B8G8R8A8; - FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(BufferSize, DiffuseGBufferFormat, FClearValueBinding::Transparent, TexCreate_SRGB, TexCreate_RenderTargetable, false)); + FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(BufferSize, DiffuseGBufferFormat, FClearValueBinding::Transparent, TexCreate_SRGB, TexCreate_RenderTargetable | TexCreate_DeltaColorCompression, false)); GRenderTargetPool.FindFreeElement(RHICmdList, Desc, GBufferC, TEXT("GBufferC")); } // Create the mask g-buffer (e.g. SSAO, subsurface scattering, wet surface mask, skylight mask, ...). { - FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(BufferSize, PF_B8G8R8A8, FClearValueBinding(FLinearColor(0, 1, 1, 1)), TexCreate_None, TexCreate_RenderTargetable, false)); + FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(BufferSize, PF_B8G8R8A8, FClearValueBinding(FLinearColor(0, 1, 1, 1)), TexCreate_None, TexCreate_RenderTargetable | TexCreate_DeltaColorCompression, false)); GRenderTargetPool.FindFreeElement(RHICmdList, Desc, GBufferD, TEXT("GBufferD")); } if (bAllowStaticLighting) { - FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(BufferSize, PF_B8G8R8A8, FClearValueBinding(FLinearColor(1, 1, 1, 1)), TexCreate_None, TexCreate_RenderTargetable, false)); + FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(BufferSize, PF_B8G8R8A8, FClearValueBinding(FLinearColor(1, 1, 1, 1)), TexCreate_None, TexCreate_RenderTargetable | TexCreate_DeltaColorCompression, false)); GRenderTargetPool.FindFreeElement(RHICmdList, Desc, GBufferE, TEXT("GBufferE")); } diff --git a/Engine/Source/Runtime/Renderer/Private/RendererScene.cpp b/Engine/Source/Runtime/Renderer/Private/RendererScene.cpp index e64625922111..3e94f20e28d3 100644 --- a/Engine/Source/Runtime/Renderer/Private/RendererScene.cpp +++ b/Engine/Source/Runtime/Renderer/Private/RendererScene.cpp @@ -163,16 +163,18 @@ FPixelInspectorData::FPixelInspectorData() { RenderTargetBufferFinalColor[i] = nullptr; RenderTargetBufferDepth[i] = nullptr; + RenderTargetBufferSceneColor[i] = nullptr; RenderTargetBufferHDR[i] = nullptr; RenderTargetBufferA[i] = nullptr; RenderTargetBufferBCDE[i] = nullptr; } } -void FPixelInspectorData::InitializeBuffers(FRenderTarget* BufferFinalColor, FRenderTarget* BufferDepth, FRenderTarget* BufferHDR, FRenderTarget* BufferA, FRenderTarget* BufferBCDE, int32 BufferIndex) +void FPixelInspectorData::InitializeBuffers(FRenderTarget* BufferFinalColor, FRenderTarget* BufferSceneColor, FRenderTarget* BufferDepth, FRenderTarget* BufferHDR, FRenderTarget* BufferA, FRenderTarget* BufferBCDE, int32 BufferIndex) { RenderTargetBufferFinalColor[BufferIndex] = BufferFinalColor; RenderTargetBufferDepth[BufferIndex] = BufferDepth; + RenderTargetBufferSceneColor[BufferIndex] = BufferSceneColor; RenderTargetBufferHDR[BufferIndex] = BufferHDR; RenderTargetBufferA[BufferIndex] = BufferA; RenderTargetBufferBCDE[BufferIndex] = BufferBCDE; @@ -202,6 +204,12 @@ void FPixelInspectorData::InitializeBuffers(FRenderTarget* BufferFinalColor, FRe check(BufferSize.X == 1 && BufferSize.Y == 1); } + if (RenderTargetBufferSceneColor[BufferIndex] != nullptr) + { + BufferSize = RenderTargetBufferSceneColor[BufferIndex]->GetSizeXY(); + check(BufferSize.X == 1 && BufferSize.Y == 1); + } + if (RenderTargetBufferHDR[BufferIndex] != nullptr) { BufferSize = RenderTargetBufferHDR[BufferIndex]->GetSizeXY(); @@ -2506,10 +2514,10 @@ void FScene::OnLevelAddedToWorld_RenderThread(FName InLevelName) } #if WITH_EDITOR -bool FScene::InitializePixelInspector(FRenderTarget* BufferFinalColor, FRenderTarget* BufferDepth, FRenderTarget* BufferHDR, FRenderTarget* BufferA, FRenderTarget* BufferBCDE, int32 BufferIndex) +bool FScene::InitializePixelInspector(FRenderTarget* BufferFinalColor, FRenderTarget* BufferSceneColor, FRenderTarget* BufferDepth, FRenderTarget* BufferHDR, FRenderTarget* BufferA, FRenderTarget* BufferBCDE, int32 BufferIndex) { //Initialize the buffers - PixelInspectorData.InitializeBuffers(BufferFinalColor, BufferDepth, BufferHDR, BufferA, BufferBCDE, BufferIndex); + PixelInspectorData.InitializeBuffers(BufferFinalColor, BufferSceneColor, BufferDepth, BufferHDR, BufferA, BufferBCDE, BufferIndex); //return true when the interface is implemented return true; } diff --git a/Engine/Source/Runtime/Renderer/Private/ScenePrivate.h b/Engine/Source/Runtime/Renderer/Private/ScenePrivate.h index 17940c9a4c45..b32223178591 100644 --- a/Engine/Source/Runtime/Renderer/Private/ScenePrivate.h +++ b/Engine/Source/Runtime/Renderer/Private/ScenePrivate.h @@ -1632,7 +1632,7 @@ typedef TMap FMaterialsToUpdateMap; public: FPixelInspectorData(); - void InitializeBuffers(FRenderTarget* BufferFinalColor, FRenderTarget* BufferDepth, FRenderTarget* BufferHDR, FRenderTarget* BufferA, FRenderTarget* BufferBCDE, int32 bufferIndex); + void InitializeBuffers(FRenderTarget* BufferFinalColor, FRenderTarget* BufferSceneColor, FRenderTarget* BufferDepth, FRenderTarget* BufferHDR, FRenderTarget* BufferA, FRenderTarget* BufferBCDE, int32 bufferIndex); bool AddPixelInspectorRequest(FPixelInspectorRequest *PixelInspectorRequest); @@ -1642,6 +1642,7 @@ typedef TMap FMaterialsToUpdateMap; FRenderTarget* RenderTargetBufferDepth[2]; FRenderTarget* RenderTargetBufferFinalColor[2]; FRenderTarget* RenderTargetBufferHDR[2]; + FRenderTarget* RenderTargetBufferSceneColor[2]; FRenderTarget* RenderTargetBufferA[2]; FRenderTarget* RenderTargetBufferBCDE[2]; }; @@ -2026,7 +2027,7 @@ public: } #if WITH_EDITOR - virtual bool InitializePixelInspector(FRenderTarget* BufferFinalColor, FRenderTarget* BufferDepth, FRenderTarget* BufferHDR, FRenderTarget* BufferA, FRenderTarget* BufferBCDE, int32 BufferIndex) override; + virtual bool InitializePixelInspector(FRenderTarget* BufferFinalColor, FRenderTarget* BufferSceneColor, FRenderTarget* BufferDepth, FRenderTarget* BufferHDR, FRenderTarget* BufferA, FRenderTarget* BufferBCDE, int32 BufferIndex) override; virtual bool AddPixelInspectorRequest(FPixelInspectorRequest *PixelInspectorRequest) override; #endif //WITH_EDITOR diff --git a/Engine/Source/Runtime/Renderer/Private/VelocityRendering.cpp b/Engine/Source/Runtime/Renderer/Private/VelocityRendering.cpp index e394084b003f..90ab154e3c18 100644 --- a/Engine/Source/Runtime/Renderer/Private/VelocityRendering.cpp +++ b/Engine/Source/Runtime/Renderer/Private/VelocityRendering.cpp @@ -828,7 +828,7 @@ FPooledRenderTargetDesc FVelocityRendering::GetRenderTargetDesc() { const FIntPoint BufferSize = FSceneRenderTargets::Get_FrameConstantsOnly().GetBufferSizeXY(); const FIntPoint VelocityBufferSize = BufferSize; // full resolution so we can reuse the existing full res z buffer - return FPooledRenderTargetDesc(FPooledRenderTargetDesc::Create2DDesc(VelocityBufferSize, PF_G16R16, FClearValueBinding::Transparent, TexCreate_None, TexCreate_RenderTargetable, false)); + return FPooledRenderTargetDesc(FPooledRenderTargetDesc::Create2DDesc(VelocityBufferSize, PF_G16R16, FClearValueBinding::Transparent, TexCreate_None, TexCreate_RenderTargetable | TexCreate_DeltaColorCompression, false)); } bool FVelocityRendering::OutputsToGBuffer() diff --git a/Engine/Source/Runtime/ShaderCore/Private/Shader.cpp b/Engine/Source/Runtime/ShaderCore/Private/Shader.cpp index 456997e8dea8..03891e2118d8 100644 --- a/Engine/Source/Runtime/ShaderCore/Private/Shader.cpp +++ b/Engine/Source/Runtime/ShaderCore/Private/Shader.cpp @@ -1577,6 +1577,11 @@ void ShaderMapAppendKeyString(EShaderPlatform Platform, FString& KeyString) KeyString += (CVar && CVar->GetValueOnAnyThread() != 0) ? TEXT("_DXTN") : TEXT("_BC5N"); } + { + static const auto CVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.ClearCoatNormal")); + KeyString += (CVar && CVar->GetValueOnAnyThread() != 0) ? TEXT("_CCBN") : TEXT("_NoCCBN"); + } + { static const auto CVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.CompileShadersForDevelopment")); KeyString += (CVar && CVar->GetValueOnAnyThread() != 0) ? TEXT("_DEV") : TEXT("_NoDEV"); diff --git a/Engine/Source/Runtime/ShaderCore/Private/ShaderCache.cpp b/Engine/Source/Runtime/ShaderCore/Private/ShaderCache.cpp index 6d6b9816daf6..f6aceec0efb9 100644 --- a/Engine/Source/Runtime/ShaderCore/Private/ShaderCache.cpp +++ b/Engine/Source/Runtime/ShaderCore/Private/ShaderCache.cpp @@ -149,6 +149,7 @@ static bool ShaderPlatformCanPrebindBoundShaderState(EShaderPlatform Platform) case SP_METAL_MRT: case SP_METAL_SM5: case SP_METAL_MACES3_1: + case SP_METAL_MACES2: { return true; } diff --git a/Engine/Source/Runtime/Slate/Private/Framework/Application/MenuStack.cpp b/Engine/Source/Runtime/Slate/Private/Framework/Application/MenuStack.cpp index b29304f02dfb..14fc431d0cfb 100644 --- a/Engine/Source/Runtime/Slate/Private/Framework/Application/MenuStack.cpp +++ b/Engine/Source/Runtime/Slate/Private/Framework/Application/MenuStack.cpp @@ -213,9 +213,11 @@ TSharedRef FMenuStack::Push(const FWidgetPath& InOwnerPath, const TShared ActiveMethod = InMethod.IsSet() ? FPopupMethodReply::UseMethod(InMethod.GetValue()) : QueryPopupMethod(InOwnerPath); // The host window is determined when a new root menu is pushed + // This must be set prior to PushInternal below, as it will be referenced if the menu being created is a new root menu. SetHostPath(InOwnerPath); } + TGuardValue Guard(bHostWindowGuard, true); return PushInternal(ParentMenu, InContent, Anchor, TransitionEffect, bFocusImmediately, ActiveMethod.GetShouldThrottle(), bIsCollapsedByParent, bEnablePerPixelTransparency); } @@ -585,6 +587,11 @@ void FMenuStack::DismissInternal(int32 FirstStackIndexToRemove) void FMenuStack::SetHostPath(const FWidgetPath& InOwnerPath) { + if (bHostWindowGuard) + { + return; + } + if ( HostPopupLayer.IsValid() ) { if ( !InOwnerPath.ContainsWidget(HostPopupLayer->GetHost()) ) diff --git a/Engine/Source/Runtime/Slate/Private/Framework/Application/SlateApplication.cpp b/Engine/Source/Runtime/Slate/Private/Framework/Application/SlateApplication.cpp index ce22fbd8d7a6..9306fee9172f 100644 --- a/Engine/Source/Runtime/Slate/Private/Framework/Application/SlateApplication.cpp +++ b/Engine/Source/Runtime/Slate/Private/Framework/Application/SlateApplication.cpp @@ -1830,9 +1830,23 @@ void FSlateApplication::AddModalWindow( TSharedRef InSlateWindow, const PlatformApplication->Cursor->Show( true ); } + //Throttle loop data + float LastLoopTime = (float)FPlatformTime::Seconds(); + const float MinThrottlePeriod = (1.0f / 60.0f); //Throttle the loop to a maximum of 60Hz + // Tick slate from here in the event that we should not return until the modal window is closed. while( InSlateWindow == GetActiveModalWindow() ) { + //Throttle the loop + const float CurrentLoopTime = FPlatformTime::Seconds(); + const float SleepTime = MinThrottlePeriod - (CurrentLoopTime-LastLoopTime); + LastLoopTime = CurrentLoopTime; + if (SleepTime > 0.0f) + { + // Sleep a bit to not eat up all CPU time + FPlatformProcess::Sleep(SleepTime); + } + FPlatformMisc::BeginNamedEvent(FColor::Magenta, "Slate::Tick"); { diff --git a/Engine/Source/Runtime/Slate/Private/Widgets/Input/SEditableText.cpp b/Engine/Source/Runtime/Slate/Private/Widgets/Input/SEditableText.cpp index 3b7464c86452..c4f66cf480c6 100644 --- a/Engine/Source/Runtime/Slate/Private/Widgets/Input/SEditableText.cpp +++ b/Engine/Source/Runtime/Slate/Private/Widgets/Input/SEditableText.cpp @@ -152,16 +152,7 @@ bool SEditableText::SupportsKeyboardFocus() const FReply SEditableText::OnFocusReceived( const FGeometry& MyGeometry, const FFocusEvent& InFocusEvent ) { - if (EditableTextLayout->HandleFocusReceived(InFocusEvent)) - { - if (InFocusEvent.GetCause() != EFocusCause::Mouse && InFocusEvent.GetCause() != EFocusCause::OtherWidgetLostFocus && bIsCaretMovedWhenGainFocus.Get()) - { - EditableTextLayout->GoTo(ETextLocation::EndOfDocument); - } - - return SWidget::OnFocusReceived(MyGeometry, InFocusEvent); - } - + EditableTextLayout->HandleFocusReceived(InFocusEvent); return FReply::Handled(); } @@ -390,6 +381,11 @@ bool SEditableText::IsMultiLineTextEdit() const return false; } +bool SEditableText::ShouldJumpCursorToEndWhenFocused() const +{ + return bIsCaretMovedWhenGainFocus.Get(false); +} + bool SEditableText::ShouldSelectAllTextWhenFocused() const { return bSelectAllTextWhenFocused.Get(false); diff --git a/Engine/Source/Runtime/Slate/Private/Widgets/Input/SSlider.cpp b/Engine/Source/Runtime/Slate/Private/Widgets/Input/SSlider.cpp index f8303fc979b4..183b06a31434 100644 --- a/Engine/Source/Runtime/Slate/Private/Widgets/Input/SSlider.cpp +++ b/Engine/Source/Runtime/Slate/Private/Widgets/Input/SSlider.cpp @@ -80,8 +80,8 @@ int32 SSlider::OnPaint( const FPaintArgs& Args, const FGeometry& AllottedGeometr const ESlateDrawEffect::Type DrawEffects = bEnabled ? ESlateDrawEffect::None : ESlateDrawEffect::DisabledEffect; // draw slider bar - auto BarTopLeft = FVector2D(SliderStartPoint.X, SliderStartPoint.Y - 1); - auto BarSize = FVector2D(SliderEndPoint.X - SliderStartPoint.X, 2); + auto BarTopLeft = FVector2D(SliderStartPoint.X, SliderStartPoint.Y - Style->BarThickness * 0.5f); + auto BarSize = FVector2D(SliderEndPoint.X - SliderStartPoint.X, Style->BarThickness); FSlateDrawElement::MakeBox( OutDrawElements, LayerId, @@ -117,12 +117,14 @@ FVector2D SSlider::ComputeDesiredSize( float ) const return SSliderDesiredSize; } + const float Thickness = FMath::Max(Style->BarThickness, Style->NormalThumbImage.ImageSize.Y); + if (Orientation == Orient_Vertical) { - return FVector2D(Style->NormalThumbImage.ImageSize.Y, SSliderDesiredSize.Y); + return FVector2D(Thickness, SSliderDesiredSize.Y); } - return FVector2D(SSliderDesiredSize.X, Style->NormalThumbImage.ImageSize.Y); + return FVector2D(SSliderDesiredSize.X, Thickness); } diff --git a/Engine/Source/Runtime/Slate/Private/Widgets/Text/SMultiLineEditableText.cpp b/Engine/Source/Runtime/Slate/Private/Widgets/Text/SMultiLineEditableText.cpp index 6b876765e3f0..91ed4284bff5 100644 --- a/Engine/Source/Runtime/Slate/Private/Widgets/Text/SMultiLineEditableText.cpp +++ b/Engine/Source/Runtime/Slate/Private/Widgets/Text/SMultiLineEditableText.cpp @@ -198,6 +198,11 @@ bool SMultiLineEditableText::IsMultiLineTextEdit() const return true; } +bool SMultiLineEditableText::ShouldJumpCursorToEndWhenFocused() const +{ + return false; +} + bool SMultiLineEditableText::ShouldSelectAllTextWhenFocused() const { return bSelectAllTextWhenFocused.Get(false); @@ -326,12 +331,7 @@ float SMultiLineEditableText::UpdateAndClampVerticalScrollBar(const float InView FReply SMultiLineEditableText::OnFocusReceived( const FGeometry& MyGeometry, const FFocusEvent& InFocusEvent ) { - // Skip the focus received code if it's due to the context menu closing - if (EditableTextLayout->HandleFocusReceived(InFocusEvent)) - { - return SWidget::OnFocusReceived(MyGeometry, InFocusEvent); - } - + EditableTextLayout->HandleFocusReceived(InFocusEvent); return FReply::Handled(); } diff --git a/Engine/Source/Runtime/Slate/Private/Widgets/Text/SlateEditableTextLayout.cpp b/Engine/Source/Runtime/Slate/Private/Widgets/Text/SlateEditableTextLayout.cpp index 1b613e7fb9eb..1d31b925085a 100644 --- a/Engine/Source/Runtime/Slate/Private/Widgets/Text/SlateEditableTextLayout.cpp +++ b/Engine/Source/Runtime/Slate/Private/Widgets/Text/SlateEditableTextLayout.cpp @@ -193,16 +193,21 @@ FSlateEditableTextLayout::~FSlateEditableTextLayout() void FSlateEditableTextLayout::SetText(const TAttribute& InText) { + const FText PreviousText = BoundText.Get(FText::GetEmpty()); BoundText = InText; - - const FText& TextToSet = BoundText.Get(FText::GetEmpty()); + const FText NewText = BoundText.Get(FText::GetEmpty()); // We need to force an update if the text doesn't match the editable text, as the editable // text may not match the current bound text since it may have been changed by the user const FText EditableText = GetEditableText(); - const bool bForceRefresh = !EditableText.ToString().Equals(TextToSet.ToString(), ESearchCase::CaseSensitive); + const bool bForceRefresh = !EditableText.ToString().Equals(NewText.ToString(), ESearchCase::CaseSensitive); - if (RefreshImpl(&TextToSet, bForceRefresh)) + // Only emit the "text changed" event if the text has actually been changed + const bool bHasTextChanged = OwnerWidget->GetSlateWidget()->HasKeyboardFocus() + ? !NewText.ToString().Equals(EditableText.ToString(), ESearchCase::CaseSensitive) + : !NewText.ToString().Equals(PreviousText.ToString(), ESearchCase::CaseSensitive); + + if (RefreshImpl(&NewText, bForceRefresh)) { // Make sure we move the cursor to the end of the new text if we had keyboard focus if (OwnerWidget->GetSlateWidget()->HasKeyboardFocus()) @@ -211,7 +216,10 @@ void FSlateEditableTextLayout::SetText(const TAttribute& InText) } // Let outsiders know that the text content has been changed - OwnerWidget->OnTextChanged(TextToSet); + if (bHasTextChanged) + { + OwnerWidget->OnTextChanged(NewText); + } } } @@ -540,6 +548,12 @@ bool FSlateEditableTextLayout::HandleFocusReceived(const FFocusEvent& InFocusEve // Store undo state to use for escape key reverts MakeUndoState(OriginalText); + // Jump to the end of the document? + if (InFocusEvent.GetCause() != EFocusCause::Mouse && InFocusEvent.GetCause() != EFocusCause::OtherWidgetLostFocus && OwnerWidget->ShouldJumpCursorToEndWhenFocused()) + { + GoTo(ETextLocation::EndOfDocument); + } + // Select All Text if (OwnerWidget->ShouldSelectAllTextWhenFocused()) { @@ -554,7 +568,7 @@ bool FSlateEditableTextLayout::HandleFocusReceived(const FFocusEvent& InFocusEve // of making sure that gets scrolled into view PositionToScrollIntoView.Reset(); - return false; + return true; } bool FSlateEditableTextLayout::HandleFocusLost(const FFocusEvent& InFocusEvent) @@ -609,6 +623,10 @@ bool FSlateEditableTextLayout::HandleFocusLost(const FFocusEvent& InFocusEvent) OwnerWidget->OnTextCommitted(EditedText, TextAction); + // Reload underlying value now it is committed (commit may alter the value) + // so it can be re-displayed in the edit box + LoadText(); + UpdateCursorHighlight(); // UpdateCursorHighlight always tries to scroll to the cursor, but we don't want that to happen when we diff --git a/Engine/Source/Runtime/Slate/Private/Widgets/Views/STableViewBase.cpp b/Engine/Source/Runtime/Slate/Private/Widgets/Views/STableViewBase.cpp index b8832d822540..4e89ff3fa214 100644 --- a/Engine/Source/Runtime/Slate/Private/Widgets/Views/STableViewBase.cpp +++ b/Engine/Source/Runtime/Slate/Private/Widgets/Views/STableViewBase.cpp @@ -688,6 +688,19 @@ void STableViewBase::SetScrollOffset( const float InScrollOffset ) } } +void STableViewBase::AddScrollOffset(const float InScrollOffsetDelta, bool RefreshList) +{ + if (FMath::IsNearlyEqual(InScrollOffsetDelta, 0.0f) == false) + { + ScrollOffset += InScrollOffsetDelta; + if (RefreshList) + { + OnTableViewScrolled.ExecuteIfBound(ScrollOffset); + RequestListRefresh(); + } + } +} + void STableViewBase::InsertWidget( const TSharedRef & WidgetToInset ) { ItemsPanel->AddSlot(0) diff --git a/Engine/Source/Runtime/Slate/Public/Framework/Application/MenuStack.h b/Engine/Source/Runtime/Slate/Public/Framework/Application/MenuStack.h index 7b3524f9007e..81f18c4d4578 100644 --- a/Engine/Source/Runtime/Slate/Public/Framework/Application/MenuStack.h +++ b/Engine/Source/Runtime/Slate/Public/Framework/Application/MenuStack.h @@ -58,6 +58,11 @@ struct FPopupTransitionEffect class FMenuStack { public: + /** Constructor */ + FMenuStack() + : bHostWindowGuard(false) + {} + /** * [Deprecated] Pushes a new menu onto the stack. Automatically removes windows from the stack that are no longer valid * Invalid windows are those that are not parents of the window menu being pushed and any windows on the same stack level @@ -408,4 +413,7 @@ private: /** Temporary ptr to a new menu created during the menu creation process. Nulled before the Push() call returns. Stops it collapsing the stack when it gets focus. */ TSharedPtr PendingNewMenu; + + /** Guard to prevent the HostWindow and HostWindowPopupPanel being set reentrantly */ + bool bHostWindowGuard; }; diff --git a/Engine/Source/Runtime/Slate/Public/Widgets/Input/SEditableText.h b/Engine/Source/Runtime/Slate/Public/Widgets/Input/SEditableText.h index da436124b915..ac69d0beaaac 100644 --- a/Engine/Source/Runtime/Slate/Public/Widgets/Input/SEditableText.h +++ b/Engine/Source/Runtime/Slate/Public/Widgets/Input/SEditableText.h @@ -284,6 +284,7 @@ public: protected: //~ Begin ISlateEditableTextWidget Interface + virtual bool ShouldJumpCursorToEndWhenFocused() const override; virtual bool ShouldSelectAllTextWhenFocused() const override; virtual bool ShouldClearTextSelectionOnFocusLoss() const override; virtual bool ShouldRevertTextOnEscape() const override; diff --git a/Engine/Source/Runtime/Slate/Public/Widgets/Text/ISlateEditableTextWidget.h b/Engine/Source/Runtime/Slate/Public/Widgets/Text/ISlateEditableTextWidget.h index b714f6d1e79b..105b3018ab6d 100644 --- a/Engine/Source/Runtime/Slate/Public/Widgets/Text/ISlateEditableTextWidget.h +++ b/Engine/Source/Runtime/Slate/Public/Widgets/Text/ISlateEditableTextWidget.h @@ -182,6 +182,9 @@ public: /** Is the text edit multi-line aware? */ virtual bool IsMultiLineTextEdit() const = 0; + /** Should the cursor be jumped to the end of the document when the widget gains focus? */ + virtual bool ShouldJumpCursorToEndWhenFocused() const = 0; + /** Should the text be selected when the widget gains focus? */ virtual bool ShouldSelectAllTextWhenFocused() const = 0; diff --git a/Engine/Source/Runtime/Slate/Public/Widgets/Text/SMultiLineEditableText.h b/Engine/Source/Runtime/Slate/Public/Widgets/Text/SMultiLineEditableText.h index 7ab5e3cbc548..58b0ebaa7a01 100644 --- a/Engine/Source/Runtime/Slate/Public/Widgets/Text/SMultiLineEditableText.h +++ b/Engine/Source/Runtime/Slate/Public/Widgets/Text/SMultiLineEditableText.h @@ -297,6 +297,7 @@ public: protected: //~ Begin ISlateEditableTextWidget Interface + virtual bool ShouldJumpCursorToEndWhenFocused() const override; virtual bool ShouldSelectAllTextWhenFocused() const override; virtual bool ShouldClearTextSelectionOnFocusLoss() const override; virtual bool ShouldRevertTextOnEscape() const override; diff --git a/Engine/Source/Runtime/Slate/Public/Widgets/Views/STableViewBase.h b/Engine/Source/Runtime/Slate/Public/Widgets/Views/STableViewBase.h index 55672bb6f9da..af95add0e35e 100644 --- a/Engine/Source/Runtime/Slate/Public/Widgets/Views/STableViewBase.h +++ b/Engine/Source/Runtime/Slate/Public/Widgets/Views/STableViewBase.h @@ -91,6 +91,9 @@ public: /** Set the scroll offset of this view (in items) */ void SetScrollOffset( const float InScrollOffset ); + /** Add the scroll offset of this view (in items) */ + void AddScrollOffset(const float InScrollOffsetDelta, bool RefreshList = false); + public: // SWidget interface diff --git a/Engine/Source/Runtime/SlateCore/Private/Fonts/FontCacheCompositeFont.cpp b/Engine/Source/Runtime/SlateCore/Private/Fonts/FontCacheCompositeFont.cpp index b9c173422b57..3f5ca4daa571 100644 --- a/Engine/Source/Runtime/SlateCore/Private/Fonts/FontCacheCompositeFont.cpp +++ b/Engine/Source/Runtime/SlateCore/Private/Fonts/FontCacheCompositeFont.cpp @@ -181,29 +181,41 @@ const FFontData& FCompositeFontCache::GetFontDataForCharacter(const FSlateFontIn { static const FFontData DummyFontData; + auto FontDataHasCharacter = [&](const FFontData& InFontData) -> bool + { +#if WITH_FREETYPE + TSharedPtr FaceAndMemory = GetFontFace(InFontData); + return FaceAndMemory.IsValid() && FT_Get_Char_Index(FaceAndMemory->GetFace(), InChar) != 0; +#else // WITH_FREETYPE + return false; +#endif // WITH_FREETYPE + }; + const FCompositeFont* const ResolvedCompositeFont = InFontInfo.GetCompositeFont(); const FCachedTypefaceData* const CachedTypefaceData = GetCachedTypefaceForCharacter(ResolvedCompositeFont, InChar); if (CachedTypefaceData) { OutScalingFactor = CachedTypefaceData->GetScalingFactor(); + const FCachedTypefaceData* const CachedDefaultTypefaceData = GetDefaultCachedTypeface(ResolvedCompositeFont); + const bool bIsDefaultTypeface = CachedTypefaceData == CachedDefaultTypefaceData; + // Try to find the correct font from the typeface const FFontData* FoundFontData = CachedTypefaceData->GetFontData(InFontInfo.TypefaceFontName); - if (FoundFontData) + if (FoundFontData && (bIsDefaultTypeface || FontDataHasCharacter(*FoundFontData))) { return *FoundFontData; } // Failing that, try and find a font by the attributes of the default font with the given name - const FCachedTypefaceData* const CachedDefaultTypefaceData = GetDefaultCachedTypeface(ResolvedCompositeFont); - if (CachedDefaultTypefaceData && CachedTypefaceData != CachedDefaultTypefaceData) + if (!bIsDefaultTypeface && CachedDefaultTypefaceData) { const FFontData* const FoundDefaultFontData = CachedDefaultTypefaceData->GetFontData(InFontInfo.TypefaceFontName); if (FoundDefaultFontData) { const TSet& DefaultFontAttributes = GetFontAttributes(*FoundDefaultFontData); FoundFontData = GetBestMatchFontForAttributes(CachedTypefaceData, DefaultFontAttributes); - if (FoundFontData) + if (FoundFontData && FontDataHasCharacter(*FoundFontData)) { return *FoundFontData; } @@ -212,10 +224,30 @@ const FFontData& FCompositeFontCache::GetFontDataForCharacter(const FSlateFontIn // Failing that, return the first font available (the "None" font) FoundFontData = CachedTypefaceData->GetFontData(NAME_None); - if (FoundFontData) + if (FoundFontData && (bIsDefaultTypeface || FontDataHasCharacter(*FoundFontData))) { return *FoundFontData; } + + // Failing that, try again using the default font (as the sub-font may not have actually supported the character we needed) + if (!bIsDefaultTypeface && CachedDefaultTypefaceData) + { + OutScalingFactor = CachedDefaultTypefaceData->GetScalingFactor(); + + // Try to find the correct font from the typeface + FoundFontData = CachedDefaultTypefaceData->GetFontData(InFontInfo.TypefaceFontName); + if (FoundFontData) + { + return *FoundFontData; + } + + // Failing that, return the first font available (the "None" font) + FoundFontData = CachedDefaultTypefaceData->GetFontData(NAME_None); + if (FoundFontData) + { + return *FoundFontData; + } + } } OutScalingFactor = 1.0f; diff --git a/Engine/Source/Runtime/SlateCore/Private/Styling/CoreStyle.cpp b/Engine/Source/Runtime/SlateCore/Private/Styling/CoreStyle.cpp index 055a40645543..2608de40ae2c 100644 --- a/Engine/Source/Runtime/SlateCore/Private/Styling/CoreStyle.cpp +++ b/Engine/Source/Runtime/SlateCore/Private/Styling/CoreStyle.cpp @@ -583,7 +583,8 @@ TSharedRef FCoreStyle::Create( const FName& InStyleSetName ) .SetNormalBarImage(FSlateColorBrush(FColor::White)) .SetDisabledBarImage(FSlateColorBrush(FLinearColor::Gray)) .SetNormalThumbImage( IMAGE_BRUSH( "Common/Button", FVector2D(8.0f, 14.0f) ) ) - .SetDisabledThumbImage( IMAGE_BRUSH( "Common/Button_Disabled", FVector2D(8.0f, 14.0f) ) ); + .SetDisabledThumbImage( IMAGE_BRUSH( "Common/Button_Disabled", FVector2D(8.0f, 14.0f) ) ) + .SetBarThickness(2.0f); Style->Set( "Slider", SliderStyle ); Style->Set( "VolumeControl", FVolumeControlStyle() diff --git a/Engine/Source/Runtime/SlateCore/Private/Styling/SlateTypes.cpp b/Engine/Source/Runtime/SlateCore/Private/Styling/SlateTypes.cpp index 7fb92127cc19..2457a57dcfc2 100644 --- a/Engine/Source/Runtime/SlateCore/Private/Styling/SlateTypes.cpp +++ b/Engine/Source/Runtime/SlateCore/Private/Styling/SlateTypes.cpp @@ -372,6 +372,7 @@ const FSearchBoxStyle& FSearchBoxStyle::GetDefault() } FSliderStyle::FSliderStyle() + : BarThickness(2.0f) { } diff --git a/Engine/Source/Runtime/SlateCore/Public/Styling/SlateTypes.h b/Engine/Source/Runtime/SlateCore/Public/Styling/SlateTypes.h index ac45c4653a30..c9dca9a20b91 100644 --- a/Engine/Source/Runtime/SlateCore/Public/Styling/SlateTypes.h +++ b/Engine/Source/Runtime/SlateCore/Public/Styling/SlateTypes.h @@ -869,6 +869,10 @@ struct SLATECORE_API FSliderStyle : public FSlateWidgetStyle UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Appearance) FSlateBrush DisabledThumbImage; FSliderStyle& SetDisabledThumbImage( const FSlateBrush& InDisabledThumbImage ){ DisabledThumbImage = InDisabledThumbImage; return *this; } + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Appearance) + float BarThickness; + FSliderStyle& SetBarThickness(float InBarThickness) { BarThickness = InBarThickness; return *this; } }; diff --git a/Engine/Source/Runtime/VulkanRHI/Private/VulkanCommandBuffer.cpp b/Engine/Source/Runtime/VulkanRHI/Private/VulkanCommandBuffer.cpp index ede40960a6a0..fe82c1fe2c70 100644 --- a/Engine/Source/Runtime/VulkanRHI/Private/VulkanCommandBuffer.cpp +++ b/Engine/Source/Runtime/VulkanRHI/Private/VulkanCommandBuffer.cpp @@ -11,17 +11,10 @@ FVulkanCmdBuffer::FVulkanCmdBuffer(FVulkanDevice* InDevice, FVulkanCommandBuffer : Device(InDevice) , CommandBufferManager(InCommandBufferManager) , CommandBufferHandle(VK_NULL_HANDLE) -#if VULKAN_USE_NEW_COMMAND_BUFFERS , State(EState::ReadyForBegin) , Fence(nullptr) , FenceSignaledCounter(0) -#else - , IsWriting(VK_FALSE) - , IsEmpty(VK_TRUE) -#endif { - check(Device); - VkCommandBufferAllocateInfo CreateCmdBufInfo; FMemory::Memzero(CreateCmdBufInfo); CreateCmdBufInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; @@ -31,27 +24,18 @@ FVulkanCmdBuffer::FVulkanCmdBuffer(FVulkanDevice* InDevice, FVulkanCommandBuffer CreateCmdBufInfo.commandPool = CommandBufferManager->GetHandle(); VERIFYVULKANRESULT(vkAllocateCommandBuffers(Device->GetInstanceHandle(), &CreateCmdBufInfo, &CommandBufferHandle)); -#if VULKAN_USE_NEW_COMMAND_BUFFERS Fence = Device->GetFenceManager().AllocateFence(); -#endif } FVulkanCmdBuffer::~FVulkanCmdBuffer() { -#if VULKAN_USE_NEW_COMMAND_BUFFERS auto& FenceManager = Device->GetFenceManager(); FenceManager.WaitAndReleaseFence(Fence, 0xffffffff); -#else - check(IsWriting == VK_FALSE); - if (CommandBufferHandle != VK_NULL_HANDLE) -#endif - { - vkFreeCommandBuffers(Device->GetInstanceHandle(), CommandBufferManager->GetHandle(), 1, &CommandBufferHandle); - CommandBufferHandle = VK_NULL_HANDLE; - } + + vkFreeCommandBuffers(Device->GetInstanceHandle(), CommandBufferManager->GetHandle(), 1, &CommandBufferHandle); + CommandBufferHandle = VK_NULL_HANDLE; } -#if VULKAN_USE_NEW_COMMAND_BUFFERS void FVulkanCmdBuffer::BeginRenderPass(const FVulkanRenderTargetLayout& Layout, VkRenderPass RenderPass, VkFramebuffer Framebuffer, const VkClearValue* AttachmentClearValues) { check(IsOutsideRenderPass()); @@ -71,24 +55,11 @@ void FVulkanCmdBuffer::BeginRenderPass(const FVulkanRenderTargetLayout& Layout, State = EState::IsInsideRenderPass; } -#else -VkCommandBuffer& FVulkanCmdBuffer::GetHandle(const VkBool32 WritingToCommandBuffer /* = true */) -{ - check(CommandBufferHandle != VK_NULL_HANDLE); - IsEmpty &= !WritingToCommandBuffer; - return CommandBufferHandle; -} -#endif - void FVulkanCmdBuffer::Begin() { -#if VULKAN_USE_NEW_COMMAND_BUFFERS check(State == EState::ReadyForBegin); -#else - check(!IsWriting); - check(IsEmpty); -#endif + VkCommandBufferBeginInfo CmdBufBeginInfo; FMemory::Memzero(CmdBufBeginInfo); CmdBufBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; @@ -96,14 +67,9 @@ void FVulkanCmdBuffer::Begin() VERIFYVULKANRESULT(vkBeginCommandBuffer(CommandBufferHandle, &CmdBufBeginInfo)); -#if VULKAN_USE_NEW_COMMAND_BUFFERS State = EState::IsInsideBegin; -#else - IsWriting = VK_TRUE; -#endif } -#if VULKAN_USE_NEW_COMMAND_BUFFERS void FVulkanCmdBuffer::RefreshFenceStatus() { if (State == EState::Submitted) @@ -121,44 +87,13 @@ void FVulkanCmdBuffer::RefreshFenceStatus() check(!Fence->IsSignaled()); } } -#else -VkBool32 FVulkanCmdBuffer::GetIsWriting() const -{ - return IsWriting; -} -VkBool32 FVulkanCmdBuffer::GetIsEmpty() const -{ - return IsEmpty; -} - -void FVulkanCmdBuffer::Reset() -{ - check(!IsWriting) - - VERIFYVULKANRESULT(vkResetCommandBuffer(GetHandle(), VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT)); - - IsEmpty = VK_TRUE; -} - -void FVulkanCmdBuffer::End() -{ - check(IsWriting) - - VERIFYVULKANRESULT(vkEndCommandBuffer(GetHandle())); - - IsWriting = VK_FALSE; - IsEmpty = VK_TRUE; -} -#endif FVulkanCommandBufferManager::FVulkanCommandBufferManager(FVulkanDevice* InDevice) : Device(InDevice) , Handle(VK_NULL_HANDLE) -#if VULKAN_USE_NEW_COMMAND_BUFFERS , ActiveCmdBuffer(nullptr) -#else -#endif + , UploadCmdBuffer(nullptr) { check(Device); @@ -170,11 +105,8 @@ FVulkanCommandBufferManager::FVulkanCommandBufferManager(FVulkanDevice* InDevice CmdPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; VERIFYVULKANRESULT(vkCreateCommandPool(Device->GetInstanceHandle(), &CmdPoolInfo, nullptr, &Handle)); -#if VULKAN_USE_NEW_COMMAND_BUFFERS ActiveCmdBuffer = Create(); ActiveCmdBuffer->Begin(); -#else -#endif } FVulkanCommandBufferManager::~FVulkanCommandBufferManager() @@ -188,6 +120,19 @@ FVulkanCommandBufferManager::~FVulkanCommandBufferManager() vkDestroyCommandPool(Device->GetInstanceHandle(), Handle, nullptr); } +FVulkanCmdBuffer* FVulkanCommandBufferManager::GetActiveCmdBuffer() +{ + if (UploadCmdBuffer) + { + check(UploadCmdBuffer->IsOutsideRenderPass()); + UploadCmdBuffer->End(); + Device->GetQueue()->Submit(UploadCmdBuffer); + UploadCmdBuffer = nullptr; + } + + return ActiveCmdBuffer; +} + FVulkanCmdBuffer* FVulkanCommandBufferManager::Create() { check(Device); @@ -197,7 +142,6 @@ FVulkanCmdBuffer* FVulkanCommandBufferManager::Create() return CmdBuffer; } -#if VULKAN_USE_NEW_COMMAND_BUFFERS void FVulkanCommandBufferManager::RefreshFenceStatus() { for (int32 Index = 0; Index < CmdBuffers.Num(); ++Index) @@ -209,6 +153,8 @@ void FVulkanCommandBufferManager::RefreshFenceStatus() void FVulkanCommandBufferManager::PrepareForNewActiveCommandBuffer() { + check(!UploadCmdBuffer); + for (int32 Index = 0; Index < CmdBuffers.Num(); ++Index) { FVulkanCmdBuffer* CmdBuffer = CmdBuffers[Index]; @@ -229,22 +175,27 @@ void FVulkanCommandBufferManager::PrepareForNewActiveCommandBuffer() ActiveCmdBuffer = Create(); ActiveCmdBuffer->Begin(); } -#else -void FVulkanCommandBufferManager::Destroy(FVulkanCmdBuffer* CmdBuffer) -{ - CmdBuffers.Remove(CmdBuffer); - check(Device); - if (CmdBuffer->GetIsWriting()) - { - CmdBuffer->End(); - } - vkFreeCommandBuffers(Device->GetInstanceHandle(), GetHandle(), 1, &CmdBuffer->CommandBufferHandle); - CmdBuffer->CommandBufferHandle = VK_NULL_HANDLE; - delete CmdBuffer; -} -void FVulkanCommandBufferManager::Submit(FVulkanCmdBuffer* CmdBuffer) +FVulkanCmdBuffer* FVulkanCommandBufferManager::GetUploadCmdBuffer() { - Device->GetQueue()->Submit(CmdBuffer); + if (!UploadCmdBuffer) + { + for (int32 Index = 0; Index < CmdBuffers.Num(); ++Index) + { + FVulkanCmdBuffer* CmdBuffer = CmdBuffers[Index]; + CmdBuffer->RefreshFenceStatus(); + if (CmdBuffer->State == FVulkanCmdBuffer::EState::ReadyForBegin) + { + UploadCmdBuffer = CmdBuffer; + UploadCmdBuffer->Begin(); + return UploadCmdBuffer; + } + } + + // All cmd buffers are being executed still + UploadCmdBuffer = Create(); + UploadCmdBuffer->Begin(); + } + + return UploadCmdBuffer; } -#endif diff --git a/Engine/Source/Runtime/VulkanRHI/Private/VulkanCommandBuffer.h b/Engine/Source/Runtime/VulkanRHI/Private/VulkanCommandBuffer.h index 65c60046f6db..fa3e97ad9d03 100644 --- a/Engine/Source/Runtime/VulkanRHI/Private/VulkanCommandBuffer.h +++ b/Engine/Source/Runtime/VulkanRHI/Private/VulkanCommandBuffer.h @@ -26,13 +26,6 @@ protected: ~FVulkanCmdBuffer(); public: -#if VULKAN_USE_NEW_COMMAND_BUFFERS -/* - inline bool IsWritable() const - { - return State == EState::IsInsideBegin || State == EState::IsInsideRenderPass; - } -*/ FVulkanCommandBufferManager* GetOwner() { return CommandBufferManager; @@ -83,12 +76,9 @@ public: { return FenceSignaledCounter; } -#else - VkCommandBuffer& GetHandle(const VkBool32 MakeDirty = true); -#endif void Begin(); -#if VULKAN_USE_NEW_COMMAND_BUFFERS + enum class EState { ReadyForBegin, @@ -97,27 +87,15 @@ public: HasEnded, Submitted, }; -#else - void Reset(); - - void End(); - - VkBool32 GetIsWriting() const; - VkBool32 GetIsEmpty() const; -#endif private: FVulkanDevice* Device; VkCommandBuffer CommandBufferHandle; -#if VULKAN_USE_NEW_COMMAND_BUFFERS EState State; VulkanRHI::FFence* Fence; uint64 FenceSignaledCounter; + void RefreshFenceStatus(); -#else - VkBool32 IsWriting; - VkBool32 IsEmpty; -#endif FVulkanCommandBufferManager* CommandBufferManager; }; @@ -129,37 +107,26 @@ public: ~FVulkanCommandBufferManager(); -#if VULKAN_USE_NEW_COMMAND_BUFFERS - FVulkanCmdBuffer* GetActiveCmdBuffer() - { - return ActiveCmdBuffer; - } + FVulkanCmdBuffer* GetActiveCmdBuffer(); + + FVulkanCmdBuffer* GetUploadCmdBuffer(); void RefreshFenceStatus(); void PrepareForNewActiveCommandBuffer(); -#else - FVulkanCmdBuffer* Create(); - void Destroy(FVulkanCmdBuffer* CmdBuffer); - - void Submit(FVulkanCmdBuffer* CmdBuffer); - -private: - friend class FVulkanCmdBuffer; - friend class FVulkanDynamicRHI; -#endif inline VkCommandPool GetHandle() const { check(Handle != VK_NULL_HANDLE); return Handle; } + private: FVulkanDevice* Device; VkCommandPool Handle; -#if VULKAN_USE_NEW_COMMAND_BUFFERS FVulkanCmdBuffer* ActiveCmdBuffer; + FVulkanCmdBuffer* UploadCmdBuffer; + FVulkanCmdBuffer* Create(); -#else -#endif + TArray CmdBuffers; }; diff --git a/Engine/Source/Runtime/VulkanRHI/Private/VulkanCommands.cpp b/Engine/Source/Runtime/VulkanRHI/Private/VulkanCommands.cpp index 4307a30bea2a..a42a2b64fcdc 100644 --- a/Engine/Source/Runtime/VulkanRHI/Private/VulkanCommands.cpp +++ b/Engine/Source/Runtime/VulkanRHI/Private/VulkanCommands.cpp @@ -524,14 +524,9 @@ void FVulkanCommandListContext::RHIDrawPrimitive(uint32 PrimitiveType, uint32 Ba if (!BSS.HasError()) #endif { -#if VULKAN_USE_NEW_COMMAND_BUFFERS auto* CmdBuffer = CommandBufferManager->GetActiveCmdBuffer(); - State.PrepareDraw(CmdBuffer, UEToVulkanType((EPrimitiveType)PrimitiveType)); + State.PrepareDraw(this, CmdBuffer, UEToVulkanType((EPrimitiveType)PrimitiveType)); vkCmdDraw(CmdBuffer->GetHandle(), NumVertices, NumInstances, BaseVertexIndex, 0); -#else - State.PrepareDraw(UEToVulkanType((EPrimitiveType)PrimitiveType)); - vkCmdDraw(Device->GetPendingState().GetCommandBuffer(), NumVertices, NumInstances, BaseVertexIndex, 0); -#endif } //if (IsImmediate()) @@ -574,14 +569,9 @@ void FVulkanCommandListContext::RHIDrawIndexedPrimitive(FIndexBufferRHIParamRef #endif { FVulkanIndexBuffer* IndexBuffer = ResourceCast(IndexBufferRHI); -#if VULKAN_USE_NEW_COMMAND_BUFFERS FVulkanCmdBuffer* Cmd = CommandBufferManager->GetActiveCmdBuffer(); VkCommandBuffer CmdBuffer = Cmd->GetHandle(); - State.PrepareDraw(Cmd, UEToVulkanType((EPrimitiveType)PrimitiveType)); -#else - VkCommandBuffer CmdBuffer = State.GetCommandBuffer(); - State.PrepareDraw(UEToVulkanType((EPrimitiveType)PrimitiveType)); -#endif + State.PrepareDraw(this, Cmd, UEToVulkanType((EPrimitiveType)PrimitiveType)); vkCmdBindIndexBuffer(CmdBuffer, IndexBuffer->GetHandle(), IndexBuffer->GetOffset(), IndexBuffer->GetIndexType()); @@ -668,20 +658,15 @@ void FVulkanCommandListContext::RHIEndDrawPrimitiveUP() FVulkanPendingState& State = Device->GetPendingState(); FVulkanBoundShaderState& Shader = State.GetBoundShaderState(); - State.SetStreamSource(0, PendingDrawPrimUPVertexAllocInfo.Buffer, PendingVertexDataStride, PendingDrawPrimUPVertexAllocInfo.Offset); + State.SetStreamSource(0, PendingDrawPrimUPVertexAllocInfo.GetHandle(), PendingVertexDataStride, PendingDrawPrimUPVertexAllocInfo.GetBindOffset()); #if VULKAN_HAS_DEBUGGING_ENABLED if(!Shader.HasError()) #endif { -#if VULKAN_USE_NEW_COMMAND_BUFFERS auto* CmdBuffer = CommandBufferManager->GetActiveCmdBuffer(); - State.PrepareDraw(CmdBuffer, UEToVulkanType((EPrimitiveType)PendingPrimitiveType)); + State.PrepareDraw(this, CmdBuffer, UEToVulkanType((EPrimitiveType)PendingPrimitiveType)); vkCmdDraw(CmdBuffer->GetHandle(), PendingNumVertices, 1, PendingMinVertexIndex, 0); -#else - State.PrepareDraw(UEToVulkanType((EPrimitiveType)PendingPrimitiveType)); - vkCmdDraw(State.GetCommandBuffer(), PendingNumVertices, 1, PendingMinVertexIndex, 0); -#endif } //if (IsImmediate()) @@ -721,22 +706,17 @@ void FVulkanCommandListContext::RHIEndDrawIndexedPrimitiveUP() FVulkanPendingState& State = Device->GetPendingState(); FVulkanBoundShaderState& Shader = State.GetBoundShaderState(); - State.SetStreamSource(0, PendingDrawPrimUPVertexAllocInfo.Buffer, PendingVertexDataStride, PendingDrawPrimUPVertexAllocInfo.Offset); + State.SetStreamSource(0, PendingDrawPrimUPVertexAllocInfo.GetHandle(), PendingVertexDataStride, PendingDrawPrimUPVertexAllocInfo.GetBindOffset()); #if VULKAN_HAS_DEBUGGING_ENABLED if(!Shader.HasError()) #endif { -#if VULKAN_USE_NEW_COMMAND_BUFFERS FVulkanCmdBuffer* CmdBuffer = CommandBufferManager->GetActiveCmdBuffer(); VkCommandBuffer Cmd = CmdBuffer->GetHandle(); - State.PrepareDraw(CmdBuffer, UEToVulkanType((EPrimitiveType)PendingPrimitiveType)); -#else - VkCommandBuffer Cmd = State.GetCommandBuffer(); - State.PrepareDraw(UEToVulkanType((EPrimitiveType)PendingPrimitiveType)); -#endif + State.PrepareDraw(this, CmdBuffer, UEToVulkanType((EPrimitiveType)PendingPrimitiveType)); uint32 NumIndices = GetVertexCountForPrimitiveCount(PendingNumPrimitives, PendingPrimitiveType); - vkCmdBindIndexBuffer(Cmd, PendingDrawPrimUPIndexAllocInfo.Buffer, PendingDrawPrimUPIndexAllocInfo.Offset, PendingPrimitiveIndexType); + vkCmdBindIndexBuffer(Cmd, PendingDrawPrimUPIndexAllocInfo.GetHandle(), PendingDrawPrimUPIndexAllocInfo.GetBindOffset(), PendingPrimitiveIndexType); vkCmdDrawIndexed(Cmd, NumIndices, 1, PendingMinVertexIndex, 0, 0); } @@ -766,11 +746,7 @@ void FVulkanCommandListContext::RHIClearMRT(bool bClearColor, int32 NumClearColo check(bClearColor ? NumClearColors > 0 : true); FVulkanPendingState& State = Device->GetPendingState(); -#if VULKAN_USE_NEW_COMMAND_BUFFERS State.UpdateRenderPass(CommandBufferManager->GetActiveCmdBuffer()); -#else - State.UpdateRenderPass(); -#endif #if VULKAN_ALLOW_MIDPASS_CLEAR VkClearRect Rect; diff --git a/Engine/Source/Runtime/VulkanRHI/Private/VulkanDebug.cpp b/Engine/Source/Runtime/VulkanRHI/Private/VulkanDebug.cpp index 3a1b6077689a..361c8c5884a9 100644 --- a/Engine/Source/Runtime/VulkanRHI/Private/VulkanDebug.cpp +++ b/Engine/Source/Runtime/VulkanRHI/Private/VulkanDebug.cpp @@ -20,34 +20,39 @@ DEFINE_LOG_CATEGORY(LogVulkanRHI); #if VULKAN_HAS_DEBUGGING_ENABLED static VkBool32 VKAPI_PTR DebugReportFunction( - VkDebugReportFlagsEXT msgFlags, - VkDebugReportObjectTypeEXT objType, - uint64_t srcObject, - size_t location, - int32 msgCode, - const ANSICHAR* pLayerPrefix, - const ANSICHAR* pMsg, - void* pUserData) + VkDebugReportFlagsEXT MsgFlags, + VkDebugReportObjectTypeEXT ObjType, + uint64_t SrcObject, + size_t Location, + int32 MsgCode, + const ANSICHAR* LayerPrefix, + const ANSICHAR* Msg, + void* UserData) { - if (msgFlags != VK_DEBUG_REPORT_ERROR_BIT_EXT && - msgFlags != VK_DEBUG_REPORT_WARNING_BIT_EXT && - msgFlags != VK_DEBUG_REPORT_INFORMATION_BIT_EXT && - msgFlags != VK_DEBUG_REPORT_DEBUG_BIT_EXT) + if (MsgFlags != VK_DEBUG_REPORT_ERROR_BIT_EXT && + MsgFlags != VK_DEBUG_REPORT_WARNING_BIT_EXT && + MsgFlags != VK_DEBUG_REPORT_INFORMATION_BIT_EXT && + MsgFlags != VK_DEBUG_REPORT_DEBUG_BIT_EXT) { ensure(0); } - if (msgFlags & VK_DEBUG_REPORT_ERROR_BIT_EXT) + if (MsgFlags & VK_DEBUG_REPORT_ERROR_BIT_EXT) { // Reaching this line should trigger a break/assert. // Check to see if this is a code we've seen before. - FString LayerCode = FString::Printf(TEXT("%s%d"), ANSI_TO_TCHAR(pLayerPrefix), msgCode); + FString LayerCode = FString::Printf(TEXT("%s%d"), ANSI_TO_TCHAR(LayerPrefix), MsgCode); static TSet SeenCodes; if (!SeenCodes.Contains(LayerCode)) { - FString Message = FString::Printf(TEXT("VulkanRHI: VK ERROR: [%s] Code %d : %s\n"), ANSI_TO_TCHAR(pLayerPrefix), msgCode, ANSI_TO_TCHAR(pMsg)); + FString Message = FString::Printf(TEXT("VulkanRHI: VK ERROR: [%s] Code %d : %s\n"), ANSI_TO_TCHAR(LayerPrefix), MsgCode, ANSI_TO_TCHAR(Msg)); FPlatformMisc::LowLevelOutputDebugStringf(*Message); + if (!FCStringAnsi::Strcmp(LayerPrefix, "MEM")) + { + ((FVulkanDynamicRHI*)GDynamicRHI)->DumpMemory(); + } + // Break debugger on first instance of each message. // Continuing will ignore the error and suppress this message in future. bool bIgnoreInFuture = true; @@ -59,32 +64,33 @@ static VkBool32 VKAPI_PTR DebugReportFunction( } return VK_FALSE; } - else if (msgFlags & VK_DEBUG_REPORT_WARNING_BIT_EXT) + else if (MsgFlags & VK_DEBUG_REPORT_WARNING_BIT_EXT) { - FString Message = FString::Printf(TEXT("VulkanRHI: VK WARNING: [%s] Code %d : %s\n"), ANSI_TO_TCHAR(pLayerPrefix), msgCode, ANSI_TO_TCHAR(pMsg)); + FString Message = FString::Printf(TEXT("VulkanRHI: VK WARNING: [%s] Code %d : %s\n"), ANSI_TO_TCHAR(LayerPrefix), MsgCode, ANSI_TO_TCHAR(Msg)); FPlatformMisc::LowLevelOutputDebugString(*Message); + return VK_FALSE; } #if VULKAN_ENABLE_API_DUMP - else if (msgFlags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) + else if (MsgFlags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) { #if !VULKAN_ENABLE_API_DUMP_DETAILED - if (!FCStringAnsi::Strcmp(pLayerPrefix, "MEM") || !FCStringAnsi::Strcmp(pLayerPrefix, "DS")) + if (!FCStringAnsi::Strcmp(LayerPrefix, "MEM") || !FCStringAnsi::Strcmp(LayerPrefix, "DS")) { // Skip Mem messages } else #endif { - FString Message = FString::Printf(TEXT("VulkanRHI: VK INFO: [%s] Code %d : %s\n"), ANSI_TO_TCHAR(pLayerPrefix), msgCode, ANSI_TO_TCHAR(pMsg)); + FString Message = FString::Printf(TEXT("VulkanRHI: VK INFO: [%s] Code %d : %s\n"), ANSI_TO_TCHAR(LayerPrefix), MsgCode, ANSI_TO_TCHAR(Msg)); FPlatformMisc::LowLevelOutputDebugString(*Message); } return VK_FALSE; } #if VULKAN_ENABLE_API_DUMP_DETAILED - else if (msgFlags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) + else if (MsgFlags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) { - FString Message = FString::Printf(TEXT("VulkanRHI: VK DEBUG: [%s] Code %d : %s\n"), ANSI_TO_TCHAR(pLayerPrefix), msgCode, ANSI_TO_TCHAR(pMsg)); + FString Message = FString::Printf(TEXT("VulkanRHI: VK DEBUG: [%s] Code %d : %s\n"), ANSI_TO_TCHAR(LayerPrefix), MsgCode, ANSI_TO_TCHAR(Msg)); FPlatformMisc::LowLevelOutputDebugString(*Message); return VK_FALSE; } diff --git a/Engine/Source/Runtime/VulkanRHI/Private/VulkanDevice.cpp b/Engine/Source/Runtime/VulkanRHI/Private/VulkanDevice.cpp index 43aaeedff143..b2284d0ccf17 100644 --- a/Engine/Source/Runtime/VulkanRHI/Private/VulkanDevice.cpp +++ b/Engine/Source/Runtime/VulkanRHI/Private/VulkanDevice.cpp @@ -14,9 +14,7 @@ FVulkanDevice::FVulkanDevice(VkPhysicalDevice InGpu) : Gpu(InGpu) , Device(VK_NULL_HANDLE) , ResourceHeapManager(this) -#if VULKAN_USE_NEW_COMMAND_BUFFERS , DeferredDeletionQueue(this) -#endif , DescriptorPool(nullptr) , DefaultSampler(VK_NULL_HANDLE) , Queue(nullptr) @@ -432,10 +430,16 @@ void FVulkanDevice::InitGPU(int32 DeviceIndex) #endif } -void FVulkanDevice::Destroy() +void FVulkanDevice::PrepareForDestroy() { WaitUntilIdle(); + delete ImmediateContext; + ImmediateContext = nullptr; +} + +void FVulkanDevice::Destroy() +{ if (TimestampQueryPool[0]) { for (int32 Index = 0; Index < NumTimestampPools; ++Index) @@ -450,9 +454,6 @@ void FVulkanDevice::Destroy() delete UBRingBuffer; - delete ImmediateContext; - ImmediateContext = nullptr; - #if VULKAN_ENABLE_PIPELINE_CACHE delete PipelineStateCache; #endif @@ -481,15 +482,6 @@ void FVulkanDevice::WaitUntilIdle() VERIFYVULKANRESULT(vkDeviceWaitIdle(Device)); } -#if VULKAN_USE_NEW_COMMAND_BUFFERS -#else -void FVulkanDevice::EndCommandBufferBlock(FVulkanCmdBuffer* CmdBuffer) -{ - check(CmdBuffer); - GetQueue()->SubmitBlocking(CmdBuffer); -} -#endif - bool FVulkanDevice::IsFormatSupported(VkFormat Format) const { const VkFormatProperties& Prop = FormatProperties[Format]; diff --git a/Engine/Source/Runtime/VulkanRHI/Private/VulkanDevice.h b/Engine/Source/Runtime/VulkanRHI/Private/VulkanDevice.h index 5fcf0183ede7..3f81ded00455 100644 --- a/Engine/Source/Runtime/VulkanRHI/Private/VulkanDevice.h +++ b/Engine/Source/Runtime/VulkanRHI/Private/VulkanDevice.h @@ -30,6 +30,7 @@ public: void CreateDevice(); + void PrepareForDestroy(); void Destroy(); void WaitUntilIdle(); @@ -40,11 +41,6 @@ public: return *PendingState; } -#if VULKAN_USE_NEW_COMMAND_BUFFERS -#else - void EndCommandBufferBlock(FVulkanCmdBuffer* CmdBuffer); -#endif - inline FVulkanQueue* GetQueue() { check(Queue); @@ -115,12 +111,10 @@ public: return ResourceHeapManager; } -#if VULKAN_USE_NEW_COMMAND_BUFFERS VulkanRHI::FDeferredDeletionQueue& GetDeferredDeletionQueue() { return DeferredDeletionQueue; } -#endif VulkanRHI::FStagingManager& GetStagingManager() { @@ -170,10 +164,11 @@ private: VkDevice Device; VulkanRHI::FDeviceMemoryManager MemoryManager; + VulkanRHI::FResourceHeapManager ResourceHeapManager; -#if VULKAN_USE_NEW_COMMAND_BUFFERS + VulkanRHI::FDeferredDeletionQueue DeferredDeletionQueue; -#endif + VulkanRHI::FStagingManager StagingManager; VulkanRHI::FFenceManager FenceManager; diff --git a/Engine/Source/Runtime/VulkanRHI/Private/VulkanIndexBuffer.cpp b/Engine/Source/Runtime/VulkanRHI/Private/VulkanIndexBuffer.cpp index fe92a890f2c8..aaae3ee03268 100644 --- a/Engine/Source/Runtime/VulkanRHI/Private/VulkanIndexBuffer.cpp +++ b/Engine/Source/Runtime/VulkanRHI/Private/VulkanIndexBuffer.cpp @@ -152,19 +152,10 @@ void FVulkanResourceMultiBuffer::Unlock() uint32 LockOffset = PendingLock.Offset; VulkanRHI::FStagingBuffer* StagingBuffer = PendingLock.StagingBuffer; PendingLock.StagingBuffer = nullptr; -#if VULKAN_USE_NEW_COMMAND_BUFFERS - FVulkanCmdBuffer* Cmd = Device->GetImmediateContext().GetCommandBufferManager()->GetActiveCmdBuffer(); + + FVulkanCmdBuffer* Cmd = Device->GetImmediateContext().GetCommandBufferManager()->GetUploadCmdBuffer(); ensure(Cmd->IsOutsideRenderPass()); VkCommandBuffer CmdBuffer = Cmd->GetHandle(); -#else - VkCommandBuffer CmdBuffer = VK_NULL_HANDLE; - FVulkanCmdBuffer* CmdObject = nullptr; - - CmdObject = Device->GetImmediateContext().GetCommandBufferManager()->Create(); - check(CmdObject); - CmdObject->Begin(); - CmdBuffer = CmdObject->GetHandle(); -#endif VkBufferCopy Region; FMemory::Memzero(Region); @@ -174,14 +165,8 @@ void FVulkanResourceMultiBuffer::Unlock() vkCmdCopyBuffer(CmdBuffer, StagingBuffer->GetHandle(), Buffers[DynamicBufferIndex]->GetHandle(), 1, &Region); //UpdateBuffer(ResourceAllocation, IndexBuffer->GetBuffer(), LockSize, LockOffset); -#if VULKAN_USE_NEW_COMMAND_BUFFERS - Device->GetDeferredDeletionQueue().EnqueueResource(Cmd, StagingBuffer); -#else - check(CmdObject); - Device->GetQueue()->SubmitBlocking(CmdObject); - Device->GetImmediateContext().GetCommandBufferManager()->Destroy(CmdObject); -#endif - Device->GetStagingManager().ReleaseBuffer(StagingBuffer); + //Device->GetDeferredDeletionQueue().EnqueueResource(Cmd, StagingBuffer); + Device->GetStagingManager().ReleaseBuffer(Cmd, StagingBuffer); } } } diff --git a/Engine/Source/Runtime/VulkanRHI/Private/VulkanMemory.cpp b/Engine/Source/Runtime/VulkanRHI/Private/VulkanMemory.cpp index 9e09fe3df1a2..5d83993eb267 100644 --- a/Engine/Source/Runtime/VulkanRHI/Private/VulkanMemory.cpp +++ b/Engine/Source/Runtime/VulkanRHI/Private/VulkanMemory.cpp @@ -94,7 +94,7 @@ namespace VulkanRHI { for (int32 Index = 0; Index < HeapInfos.Num(); ++Index) { - checkf(HeapInfos[Index].Allocations.Num() == 0, TEXT("Found %d unfreed allocations!"), HeapInfos[Index].Allocations.Num()); + ensureMsgf(HeapInfos[Index].Allocations.Num() == 0, TEXT("Found %d unfreed allocations!"), HeapInfos[Index].Allocations.Num()); } NumAllocations = 0; } @@ -172,7 +172,7 @@ namespace VulkanRHI for (int32 SubIndex = 0; SubIndex < HeapInfo.Allocations.Num(); ++SubIndex) { FDeviceMemoryAllocation* Allocation = HeapInfo.Allocations[SubIndex]; - //UE_LOG(LogVulkanRHI, Display, TEXT("\t\tAllocation %d Size %d"), SubIndex, Allocation->Size); + UE_LOG(LogVulkanRHI, Display, TEXT("\t\t%d Size %d Handle %p"), SubIndex, Allocation->Size, (void*)Allocation->Handle); TotalSize += Allocation->Size; } UE_LOG(LogVulkanRHI, Display, TEXT("\t\tTotal Allocated %.2f MB"), TotalSize / 1024.0f / 1024.0f); @@ -225,7 +225,7 @@ namespace VulkanRHI void FOldResourceAllocation::BindBuffer(FVulkanDevice* Device, VkBuffer Buffer) { - //FPlatformMisc::LowLevelOutputDebugStringf(TEXT("** vkBindBufferMemory Buf %p MemHandle %p MemOffset %d Size %u\n"), (void*)StagingBuffer->Buffer, (void*)StagingBuffer->ResourceAllocation->GetHandle(), (uint32)StagingBuffer->ResourceAllocation->GetOffset(), (uint32)MemReqs.size); + //FPlatformMisc::LowLevelOutputDebugStringf(TEXT("** vkBindBufferMemory Image %p MemHandle %p MemOffset %d Size %u\n"), (void*)Buffer, GetHandle(), GetOffset(), GetSize()); VkResult Result = vkBindBufferMemory(Device->GetInstanceHandle(), Buffer, GetHandle(), GetOffset()); #if UE_BUILD_DEBUG || UE_BUILD_DEVELOPMENT if (Result == VK_ERROR_OUT_OF_DEVICE_MEMORY || Result == VK_ERROR_OUT_OF_HOST_MEMORY) @@ -239,7 +239,7 @@ namespace VulkanRHI void FOldResourceAllocation::BindImage(FVulkanDevice* Device, VkImage Image) { - //FPlatformMisc::LowLevelOutputDebugStringf(TEXT("** vkBindImageMemory Image %p MemHandle %p MemOffset %d Size %u\n"), (void*)Image, (void*)Allocation->GetHandle(), (uint32)0, (uint32)MemoryRequirements.size); + //FPlatformMisc::LowLevelOutputDebugStringf(TEXT("** vkBindImageMemory Image %p MemHandle %p MemOffset %d Size %u\n"), (void*)Image, GetHandle(), GetOffset(), GetSize()); VkResult Result = vkBindImageMemory(Device->GetInstanceHandle(), Image, GetHandle(), GetOffset()); #if UE_BUILD_DEBUG || UE_BUILD_DEVELOPMENT if (Result == VK_ERROR_OUT_OF_DEVICE_MEMORY || Result == VK_ERROR_OUT_OF_HOST_MEMORY) @@ -467,7 +467,7 @@ namespace VulkanRHI SubAllocUsedMemory += UsedPages[Index]->UsedSize; NumSuballocations += UsedPages[Index]->ResourceAllocations.Num(); - UE_LOG(LogVulkanRHI, Display, TEXT("\t\t%d: %4d suballocs, %4d free chunks (%d used/%d free/%d max)"), Index, UsedPages[Index]->ResourceAllocations.Num(), UsedPages[Index]->FreeList.Num(), UsedPages[Index]->UsedSize, UsedPages[Index]->MaxSize - UsedPages[Index]->UsedSize, UsedPages[Index]->MaxSize); + UE_LOG(LogVulkanRHI, Display, TEXT("\t\t%d: %4d suballocs, %4d free chunks (%d used/%d free/%d max) DeviceMemory %p"), Index, UsedPages[Index]->ResourceAllocations.Num(), UsedPages[Index]->FreeList.Num(), UsedPages[Index]->UsedSize, UsedPages[Index]->MaxSize - UsedPages[Index]->UsedSize, UsedPages[Index]->MaxSize, (void*)UsedPages[Index]->DeviceMemoryAllocation->GetHandle()); } for (int32 Index = 0; Index < FreePages.Num(); ++Index) @@ -498,10 +498,13 @@ namespace VulkanRHI for (int32 Index = 0; Index < UsedPages.Num(); ++Index) { FOldResourceHeapPage* Page = UsedPages[Index]; - FOldResourceAllocation* ResourceAllocation = Page->TryAllocate(Size, Alignment, File, Line); - if (ResourceAllocation) + if (Page->DeviceMemoryAllocation->IsMapped() == bMapAllocation) { - return ResourceAllocation; + FOldResourceAllocation* ResourceAllocation = Page->TryAllocate(Size, Alignment, File, Line); + if (ResourceAllocation) + { + return ResourceAllocation; + } } } } @@ -509,17 +512,20 @@ namespace VulkanRHI for (int32 Index = 0; Index < FreePages.Num(); ++Index) { FOldResourceHeapPage* Page = FreePages[Index]; - FOldResourceAllocation* ResourceAllocation = Page->TryAllocate(Size, Alignment, File, Line); - if (ResourceAllocation) + if (Page->DeviceMemoryAllocation->IsMapped() == bMapAllocation) { - FreePages.RemoveSingleSwap(Page, false); - UsedPages.Add(Page); - return ResourceAllocation; + FOldResourceAllocation* ResourceAllocation = Page->TryAllocate(Size, Alignment, File, Line); + if (ResourceAllocation) + { + FreePages.RemoveSingleSwap(Page, false); + UsedPages.Add(Page); + return ResourceAllocation; + } } } uint32 AllocationSize = FMath::Max(Size, DefaultPageSize); #endif - FDeviceMemoryAllocation* DeviceMemoryAllocation = Owner->GetParent()->GetMemoryManager().Alloc(AllocationSize, MemoryTypeIndex, __FILE__, __LINE__); + FDeviceMemoryAllocation* DeviceMemoryAllocation = Owner->GetParent()->GetMemoryManager().Alloc(AllocationSize, MemoryTypeIndex, File, Line); auto* NewPage = new FOldResourceHeapPage(this, DeviceMemoryAllocation); UsedPages.Add(NewPage); @@ -557,7 +563,7 @@ namespace VulkanRHI const auto& MemoryProperties = MemoryManager.GetMemoryProperties(); //#todo-rco: Hack! Figure out a better way for page size - float PercentageAllocationForGPU = 0.95; + float PercentageAllocationForGPU = 0.8; uint32 NumMemoryAllocations = (uint64)Device->GetLimits().maxMemoryAllocationCount; uint32 NumGPUAllocations = (uint32)((float)NumMemoryAllocations * PercentageAllocationForGPU); @@ -565,6 +571,19 @@ namespace VulkanRHI ResourceHeaps.AddZeroed(MemoryProperties.memoryTypeCount); PageSizes.AddZeroed(MemoryProperties.memoryTypeCount); + TArray RemainingHeapSizes; + TArray NumTypesPerHeap; + for (uint32 Index = 0; Index < MemoryProperties.memoryHeapCount; ++Index) + { + RemainingHeapSizes.Add(MemoryProperties.memoryHeaps[Index].size); + NumTypesPerHeap.Add(0); + } + + for (uint32 Index = 0; Index < MemoryProperties.memoryTypeCount; ++Index) + { + ++NumTypesPerHeap[MemoryProperties.memoryTypes[Index].heapIndex]; + } + { uint32 TypeIndex = 0; VERIFYVULKANRESULT(MemoryManager.GetMemoryTypeFromProperties(TypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &TypeIndex)); @@ -573,21 +592,27 @@ namespace VulkanRHI GPUOnlyHeap = new FOldResourceHeap(this, TypeIndex, PageSize, HeapSize); ResourceHeaps[TypeIndex] = GPUOnlyHeap; PageSizes[TypeIndex] = PageSize; + RemainingHeapSizes[MemoryProperties.memoryTypes[TypeIndex].heapIndex] -= HeapSize; } + // Allocate all remaining types { - uint32 TypeIndex = 0; - VERIFYVULKANRESULT(MemoryManager.GetMemoryTypeFromProperties(TypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &TypeIndex)); + uint32 NumRemainingAllocations = NumMemoryAllocations - NumGPUAllocations; - uint64 HeapSize = MemoryProperties.memoryHeaps[MemoryProperties.memoryTypes[TypeIndex].heapIndex].size; - uint32 NumCPUAllocations = NumMemoryAllocations - NumGPUAllocations; + for (uint32 Index = 0; Index < MemoryProperties.memoryTypeCount; ++Index) + { + if (!ResourceHeaps[Index]) + { + uint32 HeapIndex = MemoryProperties.memoryTypes[Index].heapIndex; + uint64 HeapSize = RemainingHeapSizes[HeapIndex] / NumTypesPerHeap[HeapIndex]; + uint32 PageSize = HeapSize / NumRemainingAllocations; + ResourceHeaps[Index] = new FOldResourceHeap(this, Index, PageSize, HeapSize); + PageSizes[Index] = PageSize; - // Less equal than 512MB might mean PCI express bus, so clamp for smaller pages - HeapSize = FMath::Min((uint64)512 * 1024 * 1024, HeapSize); - uint32 PageSize = HeapSize / NumCPUAllocations; - CPUStagingHeap = new FOldResourceHeap(this, TypeIndex, PageSize, HeapSize); - ResourceHeaps[TypeIndex] = CPUStagingHeap; - PageSizes[TypeIndex] = PageSize; + // Always grab the last one for now... + CPUStagingHeap = ResourceHeaps[Index]; + } + } } } @@ -595,11 +620,10 @@ namespace VulkanRHI { DestroyResourceAllocations(); - delete GPUOnlyHeap; - GPUOnlyHeap = nullptr; - - delete CPUStagingHeap; - CPUStagingHeap = nullptr; + for (int32 Index = 0; Index < ResourceHeaps.Num(); ++Index) + { + delete ResourceHeaps[Index]; + } } void FResourceHeapManager::DestroyResourceAllocations() @@ -825,19 +849,20 @@ namespace VulkanRHI { FScopeLock ScopeLock(&CS); - UE_LOG(LogVulkanRHI, Display, TEXT("GPU Only Heap, Memory Type Index %d"), GPUOnlyHeap->MemoryTypeIndex); - GPUOnlyHeap->DumpMemory(); - UE_LOG(LogVulkanRHI, Display, TEXT("CPU Staging Heap, Memory Type Index %d"), CPUStagingHeap->MemoryTypeIndex); - CPUStagingHeap->DumpMemory(); + for (int32 Index = 0; Index < ResourceHeaps.Num(); ++Index) + { + UE_LOG(LogVulkanRHI, Display, TEXT("Heap %d, Memory Type Index %d"), Index, ResourceHeaps[Index]->MemoryTypeIndex); + ResourceHeaps[Index]->DumpMemory(); + } UE_LOG(LogVulkanRHI, Display, TEXT("Buffer Allocations: %d Used / %d Free"), UsedBufferAllocations.Num(), FreeBufferAllocations.Num()); if (UsedBufferAllocations.Num() > 0) { - UE_LOG(LogVulkanRHI, Display, TEXT("Index MemFlags BufferFlags #Suballocs #FreeChunks UsedSize/MaxSize")); + UE_LOG(LogVulkanRHI, Display, TEXT("Index BufferHandle DeviceMemoryHandle MemFlags BufferFlags #Suballocs #FreeChunks UsedSize/MaxSize")); for (int32 Index = 0; Index < UsedBufferAllocations.Num(); ++Index) { FBufferAllocation* BA = UsedBufferAllocations[Index]; - UE_LOG(LogVulkanRHI, Display, TEXT("%6d 0x%06x 0x%08x %6d %6d %d/%d"), Index, BA->MemoryPropertyFlags, BA->BufferUsageFlags, BA->Suballocations.Num(), BA->FreeList.Num(), BA->UsedSize, BA->MaxSize); + UE_LOG(LogVulkanRHI, Display, TEXT("%6d %p %p 0x%06x 0x%08x %6d %6d %d/%d"), Index, (void*)BA->Buffer, (void*)BA->MemoryAllocation->GetHandle(), BA->MemoryPropertyFlags, BA->BufferUsageFlags, BA->Suballocations.Num(), BA->FreeList.Num(), BA->UsedSize, BA->MaxSize); } } } @@ -958,6 +983,7 @@ namespace VulkanRHI check(ResourceAllocation); vkDestroyBuffer(DeviceHandle, Buffer, nullptr); + Buffer = VK_NULL_HANDLE; ResourceAllocation = nullptr; //Memory.Free(Allocation); } @@ -965,9 +991,7 @@ namespace VulkanRHI FStagingManager::~FStagingManager() { check(UsedStagingBuffers.Num() == 0); -#if VULKAN_USE_NEW_COMMAND_BUFFERS check(PendingFreeStagingBuffers.Num() == 0); -#endif check(FreeStagingBuffers.Num() == 0); } @@ -1034,7 +1058,6 @@ namespace VulkanRHI return StagingBuffer; } -#if VULKAN_USE_NEW_COMMAND_BUFFERS void FStagingManager::ReleaseBuffer(FVulkanCmdBuffer* CmdBuffer, FStagingBuffer*& StagingBuffer) { FScopeLock Lock(&GAllocationLock); @@ -1045,19 +1068,37 @@ namespace VulkanRHI Entry->Resource = StagingBuffer; StagingBuffer = nullptr; } -#else - void FStagingManager::ReleaseBuffer(FStagingBuffer*& StagingBuffer) + +#if UE_BUILD_DEBUG || UE_BUILD_DEVELOPMENT + void FStagingManager::DumpMemory() { - FScopeLock Lock(&GAllocationLock); - UsedStagingBuffers.RemoveSingleSwap(StagingBuffer); - FreeStagingBuffers.Add(StagingBuffer); - StagingBuffer = nullptr; + UE_LOG(LogVulkanRHI, Display, TEXT("StagingManager %d Used %d Pending Free %d Free"), UsedStagingBuffers.Num(), PendingFreeStagingBuffers.Num(), FreeStagingBuffers.Num()); + UE_LOG(LogVulkanRHI, Display, TEXT("Used BufferHandle ResourceAllocation")); + for (int32 Index = 0; Index < UsedStagingBuffers.Num(); ++Index) + { + FStagingBuffer* Buffer = UsedStagingBuffers[Index]; + UE_LOG(LogVulkanRHI, Display, TEXT("%6d %p %p"), Index, (void*)Buffer->GetHandle(), (void*)Buffer->ResourceAllocation->GetHandle()); + } + + UE_LOG(LogVulkanRHI, Display, TEXT("Pending CmdBuffer Fence BufferHandle ResourceAllocation")); + for (int32 Index = 0; Index < PendingFreeStagingBuffers.Num(); ++Index) + { + FPendingItem& Item = PendingFreeStagingBuffers[Index]; + FStagingBuffer* Buffer = (FStagingBuffer*)Item.Resource; + UE_LOG(LogVulkanRHI, Display, TEXT("%6d %p %p %p %p"), Index, (void*)Item.CmdBuffer->GetHandle(), (void*)Item.FenceCounter, (void*)Buffer->GetHandle(), (void*)Buffer->ResourceAllocation->GetHandle()); + } + + UE_LOG(LogVulkanRHI, Display, TEXT("Free BufferHandle ResourceAllocation")); + for (int32 Index = 0; Index < FreeStagingBuffers.Num(); ++Index) + { + FStagingBuffer* Buffer = FreeStagingBuffers[Index]; + UE_LOG(LogVulkanRHI, Display, TEXT("%6d %p %p"), Index, (void*)Buffer->GetHandle(), (void*)Buffer->ResourceAllocation->GetHandle()); + } } #endif void FStagingManager::ProcessPendingFree(bool bImmediately) { -#if VULKAN_USE_NEW_COMMAND_BUFFERS FScopeLock Lock(&GAllocationLock); for (int32 Index = PendingFreeStagingBuffers.Num() - 1; Index >= 0; --Index) { @@ -1071,20 +1112,6 @@ namespace VulkanRHI //#todo-rco: Release buffers back to OS... } } - - for (int32 Index = PendingFreeStagingImages.Num() - 1; Index >= 0; --Index) - { - FPendingItem& Entry = PendingFreeStagingImages[Index]; - if (bImmediately || !Entry.CmdBuffer || Entry.FenceCounter < Entry.CmdBuffer->GetFenceSignaledCounter()) - { - auto* StagingImage = (FStagingImage*)Entry.Resource; - PendingFreeStagingImages.RemoveAtSwap(Index, 1, false); - FreeStagingImages.Add(StagingImage); - - //#todo-rco: Release images back to OS... - } - } -#endif } FFence::FFence(FVulkanDevice* InDevice, FFenceManager* InOwner) @@ -1228,7 +1255,6 @@ namespace VulkanRHI void FDeferredDeletionQueue::EnqueueResource(FVulkanCmdBuffer* CmdBuffer, FRefCount* Resource) { -#if VULKAN_USE_NEW_COMMAND_BUFFERS Resource->AddRef(); FEntry Entry; @@ -1239,15 +1265,13 @@ namespace VulkanRHI FScopeLock ScopeLock(&CS); Entries.Add(Entry); } -#endif } void FDeferredDeletionQueue::ReleaseResources(/*bool bDeleteImmediately*/) { -#if VULKAN_USE_NEW_COMMAND_BUFFERS FScopeLock ScopeLock(&CS); - // Traverse list backwards to the swap switches to elements already tested + // Traverse list backwards so the swap switches to elements already tested for (int32 Index = Entries.Num() - 1; Index >= 0; --Index) { FEntry* Entry = &Entries[Index]; @@ -1257,7 +1281,6 @@ namespace VulkanRHI Entries.RemoveAtSwap(Index, 1, false); } } -#endif } FTempFrameAllocationBuffer::FTempFrameAllocationBuffer(FVulkanDevice* InDevice, uint32 InSize) @@ -1268,26 +1291,25 @@ namespace VulkanRHI { for (int32 Index = 0; Index < NUM_RENDER_BUFFERS; ++Index) { - Buffer[Index] = InDevice->GetStagingManager().AcquireBuffer(InSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT); - MappedData[Index] = (uint8*)Buffer[Index]->GetMappedPointer(); + BufferSuballocations[Index] = InDevice->GetResourceHeapManager().AllocateBuffer(InSize, + VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, + __FILE__, __LINE__); + MappedData[Index] = (uint8*)BufferSuballocations[Index]->GetMappedPointer(); CurrentData[Index] = MappedData[Index]; } } FTempFrameAllocationBuffer::~FTempFrameAllocationBuffer() { - check(!Buffer[0]); + Destroy(); } void FTempFrameAllocationBuffer::Destroy() { for (int32 Index = 0; Index < NUM_RENDER_BUFFERS; ++Index) { -#if VULKAN_USE_NEW_COMMAND_BUFFERS - GetParent()->GetStagingManager().ReleaseBuffer(nullptr, Buffer[Index]); -#else - GetParent()->GetStagingManager().ReleaseBuffer(Buffer[Index]); -#endif + BufferSuballocations[Index] = nullptr; } } @@ -1297,8 +1319,8 @@ namespace VulkanRHI if (AlignedData + InSize <= MappedData[BufferIndex] + Size) { OutInfo.Data = AlignedData; - OutInfo.Buffer = Buffer[BufferIndex]->GetHandle(); - OutInfo.Offset = (uint32)(AlignedData - MappedData[BufferIndex]); + OutInfo.BufferSuballocation = BufferSuballocations[BufferIndex]; + OutInfo.CurrentOffset = (uint32)(AlignedData - MappedData[BufferIndex]); CurrentData[BufferIndex] = AlignedData + InSize; PeakUsed = FMath::Max(PeakUsed, (uint32)(CurrentData[BufferIndex] - MappedData[BufferIndex])); return true; diff --git a/Engine/Source/Runtime/VulkanRHI/Private/VulkanPendingState.cpp b/Engine/Source/Runtime/VulkanRHI/Private/VulkanPendingState.cpp index e209a6912e32..628dcc780057 100644 --- a/Engine/Source/Runtime/VulkanRHI/Private/VulkanPendingState.cpp +++ b/Engine/Source/Runtime/VulkanRHI/Private/VulkanPendingState.cpp @@ -262,24 +262,10 @@ FVulkanPendingState::FVulkanPendingState(FVulkanDevice* InDevice) , bBeginRenderPass(false) , bChangeRenderTarget(false) , GlobalUniformPool(nullptr) -#if VULKAN_USE_NEW_COMMAND_BUFFERS -#else - , CurrentCmdBufferIndex(0) -#endif , bScissorEnable(false) { check(Device); -#if VULKAN_USE_NEW_COMMAND_BUFFERS - // State doesn't own or manage cmd buffers -#else - for (uint32 CmdBufferIndex = 0; CmdBufferIndex < VULKAN_NUM_COMMAND_BUFFERS; ++CmdBufferIndex) - { - //#todo-rco: FIX ME! - CmdBuffers[CmdBufferIndex] = Device->GetImmediateContext().GetCommandBufferManager()->Create(); - } -#endif - Reset(); // Create the global uniform pool @@ -290,16 +276,6 @@ FVulkanPendingState::~FVulkanPendingState() { check(Device); -#if VULKAN_USE_NEW_COMMAND_BUFFERS - // State doesn't own or manage cmd buffers -#else - for (uint32 CmdBufferIndex = 0; CmdBufferIndex < VULKAN_NUM_COMMAND_BUFFERS; ++CmdBufferIndex) - { - //#todo-rco: FIX ME! - Device->GetImmediateContext().GetCommandBufferManager()->Destroy(CmdBuffers[CmdBufferIndex]); - CmdBuffers[CmdBufferIndex] = nullptr; - } -#endif //Reset(); /* @@ -331,32 +307,21 @@ FVulkanPendingState::~FVulkanPendingState() RenderPassMap.Empty(0); } -FVulkanDescriptorSets* FVulkanPendingState::AllocateDescriptorSet(const FVulkanBoundShaderState* BoundShaderState) -{ - FVulkanDescriptorSets* DescriptorSet = new FVulkanDescriptorSets(Device, BoundShaderState, Device->GetDescriptorPool()); - return DescriptorSet; -} - -void FVulkanPendingState::DeallocateDescriptorSet(FVulkanDescriptorSets*& DescriptorSet, const FVulkanBoundShaderState* BoundShaderState) -{ - delete DescriptorSet; - DescriptorSet = nullptr; -} - FVulkanGlobalUniformPool& FVulkanPendingState::GetGlobalUniformPool() { check(GlobalUniformPool); return *GlobalUniformPool; } -#if VULKAN_USE_NEW_COMMAND_BUFFERS -void FVulkanPendingState::RenderPassBegin(FVulkanCmdBuffer* CmdBuffer) -#else -void FVulkanPendingState::RenderPassBegin() -#endif +bool FVulkanPendingState::RenderPassBegin(FVulkanCmdBuffer* CmdBuffer) { check(!bBeginRenderPass); + if (RTInfo.NumColorRenderTargets == 0 && !RTInfo.DepthStencilRenderTarget.Texture) + { + return false; + } + FVulkanRenderTargetLayout DesiredLayout(RTInfo); FVulkanRenderPass* NewRenderPass = GetOrCreateRenderPass(DesiredLayout); @@ -423,29 +388,19 @@ void FVulkanPendingState::RenderPassBegin() // if either bit is set that we have a depth buffer attached } -#if VULKAN_USE_NEW_COMMAND_BUFFERS CmdBuffer->BeginRenderPass(CurrentState.RenderPass->GetLayout(), CurrentState.RenderPass->GetHandle(), CurrentState.FrameBuffer->GetHandle(), ClearValues); -#else - CurrentState.RenderPass->Begin(GetCurrentCommandBuffer(), CurrentState.FrameBuffer->GetHandle(), ClearValues); -#endif + bBeginRenderPass = true; + + return true; } -#if VULKAN_USE_NEW_COMMAND_BUFFERS void FVulkanPendingState::RenderPassEnd(FVulkanCmdBuffer* CmdBuffer) { check(bBeginRenderPass); CmdBuffer->EndRenderPass(); bBeginRenderPass = false; } -#else -void FVulkanPendingState::RenderPassEnd() -{ - check(bBeginRenderPass); - CurrentState.RenderPass->End(GetCurrentCommandBuffer()); - bBeginRenderPass = false; -} -#endif // Expected to be called after render pass has been ended // and only from "FVulkanDynamicRHI::RHIEndDrawingViewport()" @@ -455,14 +410,6 @@ void FVulkanPendingState::Reset() CurrentState.Reset(); -#if VULKAN_USE_NEW_COMMAND_BUFFERS - // State doesn't own or manage cmd buffers -#else - CurrentCmdBufferIndex = (CurrentCmdBufferIndex + 1) % VULKAN_NUM_COMMAND_BUFFERS; - - GetCurrentCommandBuffer().Reset(); - GetCurrentCommandBuffer().Begin(); -#endif FMemory::Memzero(PendingStreams); } @@ -624,11 +571,7 @@ inline void FVulkanBoundShaderState::BindDescriptorSets(FVulkanCmdBuffer* Cmd) CurrDescriptorSets->Bind(Cmd, this); } -#if VULKAN_USE_NEW_COMMAND_BUFFERS -void FVulkanPendingState::PrepareDraw(FVulkanCmdBuffer* Cmd, VkPrimitiveTopology Topology) -#else -void FVulkanPendingState::PrepareDraw(VkPrimitiveTopology Topology) -#endif +void FVulkanPendingState::PrepareDraw(FVulkanCommandListContext* CmdListContext, FVulkanCmdBuffer* Cmd, VkPrimitiveTopology Topology) { SCOPE_CYCLE_COUNTER(STAT_VulkanDrawCallPrepareTime); @@ -636,14 +579,10 @@ void FVulkanPendingState::PrepareDraw(VkPrimitiveTopology Topology) SetKeyBits(CurrentKey, OFFSET_POLYTYPE, NUMBITS_POLYTYPE, Topology); //@TODO: let's try not to do this per draw call? -#if VULKAN_USE_NEW_COMMAND_BUFFERS UpdateRenderPass(Cmd); -#else - UpdateRenderPass(); -#endif check(CurrentState.Shader); - CurrentState.Shader->UpdateDescriptorSets(GlobalUniformPool); + CurrentState.Shader->UpdateDescriptorSets(CmdListContext, Cmd, GlobalUniformPool); // let the BoundShaderState return a pipeline object for the full current state of things CurrentState.InputAssembly.topology = Topology; @@ -653,10 +592,6 @@ void FVulkanPendingState::PrepareDraw(VkPrimitiveTopology Topology) { SCOPE_CYCLE_COUNTER(STAT_VulkanPipelineBind); -#if VULKAN_USE_NEW_COMMAND_BUFFERS -#else - auto* Cmd = &GetCurrentCommandBuffer(); -#endif Pipeline->UpdateDynamicStates(Cmd, CurrentState); VkPipeline NewPipeline = Pipeline->GetHandle(); @@ -685,7 +620,7 @@ void FVulkanPendingState::PrepareDraw(VkPrimitiveTopology Topology) void FVulkanPendingState::SubmitPendingCommandBuffers(FVulkanPendingState::TCallback* Callback, void* CallbackUserData) { -#if VULKAN_USE_NEW_COMMAND_BUFFERS +#if 1//VULKAN_USE_NEW_COMMAND_BUFFERS check(0); #else if (IsRenderPassActive()) @@ -706,7 +641,7 @@ void FVulkanPendingState::SubmitPendingCommandBuffers(FVulkanPendingState::TCall void FVulkanPendingState::SubmitPendingCommandBuffersBlockingNoRenderPass() { -#if VULKAN_USE_NEW_COMMAND_BUFFERS +#if 1//VULKAN_USE_NEW_COMMAND_BUFFERS check(0); #else check(Device); @@ -717,13 +652,25 @@ void FVulkanPendingState::SubmitPendingCommandBuffersBlockingNoRenderPass() void FVulkanPendingState::SetRenderTargetsInfo(const FRHISetRenderTargetsInfo& InRTInfo) { //#todo-rco: Check perf -#if !VULKAN_USE_NEW_COMMAND_BUFFERS +#if 0//!VULKAN_USE_NEW_COMMAND_BUFFERS if (NeedsToSetRenderTarget(InRTInfo) == false) { return; } #endif +#if 1 + // Back this up for the next SetRenderTarget + RTInfo = InRTInfo; + if (RTInfo.NumColorRenderTargets == 1 && !RTInfo.ColorRenderTarget[0].Texture) + { + RTInfo.ColorRenderTarget[0].LoadAction = ERenderTargetLoadAction::ENoAction; + RTInfo.ColorRenderTarget[0].StoreAction = ERenderTargetStoreAction::ENoAction; + check(!RTInfo.bClearColor); + --RTInfo.NumColorRenderTargets; + } + bChangeRenderTarget = true; +#else //@NOTE: this is only needed for the work-around below FRHISetRenderTargetsInfo PrevRTInfo = RTInfo; @@ -743,6 +690,7 @@ void FVulkanPendingState::SetRenderTargetsInfo(const FRHISetRenderTargetsInfo& I check(rtv.Texture); } } +#endif } bool FVulkanPendingState::NeedsToSetRenderTarget(const FRHISetRenderTargetsInfo& InRTInfo) @@ -846,19 +794,6 @@ FVulkanRenderPass& FVulkanPendingState::GetRenderPass() return *CurrentState.RenderPass; } -#if VULKAN_USE_NEW_COMMAND_BUFFERS -#else -VkCommandBuffer& FVulkanPendingState::GetCommandBuffer() -{ - return GetCurrentCommandBuffer().GetHandle(); -} - -const VkBool32 FVulkanPendingState::GetIsCommandBufferEmpty() const -{ - return GetCurrentCommandBuffer().GetIsEmpty(); -} -#endif - void FVulkanPendingState::SetViewport(uint32 MinX, uint32 MinY, float MinZ, uint32 MaxX, uint32 MaxY, float MaxZ) { VkViewport& vp = CurrentState.Viewport; diff --git a/Engine/Source/Runtime/VulkanRHI/Private/VulkanPendingState.h b/Engine/Source/Runtime/VulkanRHI/Private/VulkanPendingState.h index 45e9e1301a99..d4e6248f43cb 100644 --- a/Engine/Source/Runtime/VulkanRHI/Private/VulkanPendingState.h +++ b/Engine/Source/Runtime/VulkanRHI/Private/VulkanPendingState.h @@ -20,33 +20,17 @@ public: ~FVulkanPendingState(); - FVulkanDescriptorSets* AllocateDescriptorSet(const FVulkanBoundShaderState* BoundShaderState); - void DeallocateDescriptorSet(FVulkanDescriptorSets*& DescriptorSet, const FVulkanBoundShaderState* BoundShaderState); - FVulkanGlobalUniformPool& GetGlobalUniformPool(); void SetRenderTargetsInfo(const FRHISetRenderTargetsInfo& InRTInfo); void Reset(); -#if VULKAN_USE_NEW_COMMAND_BUFFERS - void RenderPassBegin(FVulkanCmdBuffer* CmdBuffer); + bool RenderPassBegin(FVulkanCmdBuffer* CmdBuffer); - void PrepareDraw(FVulkanCmdBuffer* CmdBuffer, VkPrimitiveTopology Topology); + void PrepareDraw(FVulkanCommandListContext* CmdListContext, FVulkanCmdBuffer* CmdBuffer, VkPrimitiveTopology Topology); void RenderPassEnd(FVulkanCmdBuffer* CmdBuffer); -#else - // Needs to be called before "PrepareDraw" and also starts writing in to the command buffer - void RenderPassBegin(); - - // Needs to be called before any calling a draw-call - // Binds graphics pipeline - void PrepareDraw(VkPrimitiveTopology Topology); - - // Is currently linked to the command buffer - // Will get called in RHIEndDrawingViewport through SubmitPendingCommandBuffers - void RenderPassEnd(); -#endif inline bool IsRenderPassActive() const { @@ -76,15 +60,8 @@ public: // Retuns constructed render pass FVulkanRenderPass& GetRenderPass(); -#if VULKAN_USE_NEW_COMMAND_BUFFERS -#else - // Returns currently bound command buffer - VkCommandBuffer& GetCommandBuffer(); - const VkBool32 GetIsCommandBufferEmpty() const; -#endif FVulkanFramebuffer* GetFrameBuffer(); -#if VULKAN_USE_NEW_COMMAND_BUFFERS inline void UpdateRenderPass(FVulkanCmdBuffer* CmdBuffer) { //#todo-rco: Don't test here, move earlier to SetRenderTarget @@ -95,7 +72,10 @@ public: RenderPassEnd(CmdBuffer); } - RenderPassBegin(CmdBuffer); + if (!RenderPassBegin(CmdBuffer)) + { + return; + } bChangeRenderTarget = false; } if (!bBeginRenderPass) @@ -104,22 +84,6 @@ public: bChangeRenderTarget = false; } } -#else - inline void UpdateRenderPass() - { - //#todo-rco: Don't test here, move earlier to SetRenderTarget - if (bChangeRenderTarget) - { - if (bBeginRenderPass) - { - RenderPassEnd(); - } - - RenderPassBegin(); - bChangeRenderTarget = false; - } - } -#endif inline const FVulkanPipelineGraphicsKey& GetCurrentKey() const { @@ -178,36 +142,6 @@ public: void InitFrame(); -#if VULKAN_USE_NEW_COMMAND_BUFFERS -#else - inline FVulkanCmdBuffer& GetCommandBuffer(uint32 Index) - { - check(IndexGetInstanceHandle(), FamilyIndex, InQueueIndex, &Queue); - -#if VULKAN_USE_NEW_COMMAND_BUFFERS -#else - AcquireNextImageKHR = (PFN_vkAcquireNextImageKHR)(void*)vkGetDeviceProcAddr(Device->GetInstanceHandle(), "vkAcquireNextImageKHR"); - check(AcquireNextImageKHR); - - QueuePresentKHR = (PFN_vkQueuePresentKHR)(void*)vkGetDeviceProcAddr(Device->GetInstanceHandle(), "vkQueuePresentKHR"); - check(QueuePresentKHR); -#endif } FVulkanQueue::~FVulkanQueue() { check(Device); - -#if VULKAN_USE_NEW_COMMAND_BUFFERS -#else - if (Fences[CurrentFenceIndex] != VK_NULL_HANDLE) - { - Device->GetFenceManager().WaitForFence(Fences[CurrentFenceIndex], UINT32_MAX); - } - - for (int BufferIndex = 0; BufferIndex < VULKAN_NUM_IMAGE_BUFFERS; ++BufferIndex) - { - delete ImageAcquiredSemaphore[BufferIndex]; - ImageAcquiredSemaphore[BufferIndex] = nullptr; - delete RenderingCompletedSemaphore[BufferIndex]; - RenderingCompletedSemaphore[BufferIndex] = nullptr; - - if (Fences[BufferIndex]) - { - Device->GetFenceManager().ReleaseFence(Fences[BufferIndex]); - Fences[BufferIndex] = nullptr; - } - } -#endif } -#if VULKAN_USE_NEW_COMMAND_BUFFERS -#else -uint32 FVulkanQueue::AquireImageIndex(FVulkanSwapChain* Swapchain) -{ - check(Device); - check(Swapchain); - - //@TODO: Clean up code once the API and SDK is more robust. - //@SMEDIS: Since we only have one queue, we shouldn't actually need any semaphores in this .cpp file. - //@SMEDIS: I also don't think we need the Fences[] array. - - CurrentFenceIndex = (CurrentFenceIndex + 1) % VULKAN_NUM_IMAGE_BUFFERS; - - if (Fences[CurrentFenceIndex] != VK_NULL_HANDLE) - { - #if 0 - VkResult Result = vkGetFenceStatus(Device->GetInstanceHandle(), Fences[CurrentFenceIndex]); - if(Result >= VK_SUCCESS) - #endif - { - // Grab the next fence and re-use it. - Device->GetFenceManager().WaitForFence(Fences[CurrentFenceIndex], UINT32_MAX); - Device->GetFenceManager().ResetFence(Fences[CurrentFenceIndex]); - } - } - - // Get the index of the next swapchain image we should render to. - // We'll wait with an "infinite" timeout, the function will block until an image is ready. - // The ImageAcquiredSemaphore[ImageAcquiredSemaphoreIndex] will get signaled when the image is ready (upon function return). - // The Fences[CurrentFenceIndex] will also get signaled when the image is ready (upon function return). - // Note: Queues can still be filled in on the CPU side, but won't execute until the semaphore is signaled. - CurrentImageIndex = -1; - VkResult Result = AcquireNextImageKHR( - Device->GetInstanceHandle(), - Swapchain->SwapChain, - UINT64_MAX, - ImageAcquiredSemaphore[CurrentFenceIndex]->GetHandle(), - VK_NULL_HANDLE, - &CurrentImageIndex); - checkf(Result == VK_SUCCESS || Result == VK_SUBOPTIMAL_KHR, TEXT("AcquireNextImageKHR failed Result = %d"), int32(Result)); - - return CurrentImageIndex; -} -#endif - -#if VULKAN_USE_NEW_COMMAND_BUFFERS void FVulkanQueue::Submit(FVulkanCmdBuffer* CmdBuffer) { check(CmdBuffer->HasEnded()); @@ -155,65 +59,10 @@ void FVulkanQueue::Submit(FVulkanCmdBuffer* CmdBuffer) CmdBuffer->GetOwner()->RefreshFenceStatus(); } -#else -void FVulkanQueue::Submit(FVulkanCmdBuffer* CmdBuffer) -{ - check(CmdBuffer); - CmdBuffer->End(); - - const VkCommandBuffer CmdBuffers[] = { CmdBuffer->GetHandle(false) }; - const VkPipelineStageFlags WaitDstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - VkSubmitInfo SubmitInfo; - FMemory::Memzero(SubmitInfo); - - VkSemaphore Local[2] = - { - ImageAcquiredSemaphore[CurrentFenceIndex]->GetHandle(), - RenderingCompletedSemaphore[CurrentFenceIndex]->GetHandle() - }; - SubmitInfo.waitSemaphoreCount = 1; // 0; // 1; - SubmitInfo.pWaitSemaphores = &Local[0]; - SubmitInfo.pWaitDstStageMask = &WaitDstStageMask; - SubmitInfo.signalSemaphoreCount = 1; // 0; // 1; - SubmitInfo.pSignalSemaphores = &Local[1]; - SubmitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - SubmitInfo.commandBufferCount = 1; - SubmitInfo.pCommandBuffers = CmdBuffers; - - if (!Fences[CurrentFenceIndex]) - { - Fences[CurrentFenceIndex] = Device->GetFenceManager().AllocateFence(); - } - VERIFYVULKANRESULT(vkQueueSubmit(Queue, 1, &SubmitInfo, Fences[CurrentFenceIndex]->GetHandle())); - - if (GWaitForIdleOnSubmit != 0) - { - VERIFYVULKANRESULT(vkQueueWaitIdle(Queue)); - } -} -#endif - -#if !VULKAN_USE_NEW_COMMAND_BUFFERS -void FVulkanQueue::Submit2(VkCommandBuffer CmdBuffer, VulkanRHI::FFence* Fence) -{ - VkSubmitInfo SubmitInfo; - FMemory::Memzero(SubmitInfo); - SubmitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - SubmitInfo.commandBufferCount = 1; - SubmitInfo.pCommandBuffers = &CmdBuffer; - check(!Fence || !Fence->IsSignaled()); - VERIFYVULKANRESULT(vkQueueSubmit(Queue, 1, &SubmitInfo, Fence ? Fence->GetHandle() : VK_NULL_HANDLE)); - - if (GWaitForIdleOnSubmit != 0) - { - VERIFYVULKANRESULT(vkQueueWaitIdle(Queue)); - } -} -#endif void FVulkanQueue::SubmitBlocking(FVulkanCmdBuffer* CmdBuffer) { -#if VULKAN_USE_NEW_COMMAND_BUFFERS +#if 1//VULKAN_USE_NEW_COMMAND_BUFFERS check(0); #else check(CmdBuffer); @@ -236,25 +85,3 @@ void FVulkanQueue::SubmitBlocking(FVulkanCmdBuffer* CmdBuffer) Device->GetFenceManager().ReleaseFence(Fence); #endif } - -#if VULKAN_USE_NEW_COMMAND_BUFFERS -#else -void FVulkanQueue::Present(FVulkanSwapChain* Swapchain, uint32 ImageIndex) -{ - check(Swapchain); - - VkPresentInfoKHR Info; - FMemory::Memzero(Info); - Info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; - Info.waitSemaphoreCount = 1; // 0; // 1; - VkSemaphore Local = RenderingCompletedSemaphore[CurrentFenceIndex]->GetHandle(); - Info.pWaitSemaphores = &Local; - Info.swapchainCount = 1; - Info.pSwapchains = &Swapchain->SwapChain; - Info.pImageIndices = &ImageIndex; - VkResult OutResult = VK_SUCCESS; - Info.pResults = &OutResult; - VERIFYVULKANRESULT(QueuePresentKHR(Queue, &Info)); - VERIFYVULKANRESULT(OutResult); -} -#endif diff --git a/Engine/Source/Runtime/VulkanRHI/Private/VulkanQueue.h b/Engine/Source/Runtime/VulkanRHI/Private/VulkanQueue.h index 178565ae5d27..524e8e1f11a0 100644 --- a/Engine/Source/Runtime/VulkanRHI/Private/VulkanQueue.h +++ b/Engine/Source/Runtime/VulkanRHI/Private/VulkanQueue.h @@ -34,31 +34,12 @@ public: void SubmitBlocking(FVulkanCmdBuffer* CmdBuffer); -#if VULKAN_USE_NEW_COMMAND_BUFFERS -#else - void Submit2(VkCommandBuffer CmdBuffer, VulkanRHI::FFence* Fence); - uint32 AquireImageIndex(FVulkanSwapChain* Swapchain); - void Present(FVulkanSwapChain* Swapchain, uint32 ImageIndex); -#endif - inline VkQueue GetHandle() const { return Queue; } private: -#if VULKAN_USE_NEW_COMMAND_BUFFERS -#else - PFN_vkAcquireNextImageKHR AcquireNextImageKHR; - PFN_vkQueuePresentKHR QueuePresentKHR; - - FVulkanSemaphore* ImageAcquiredSemaphore[VULKAN_NUM_IMAGE_BUFFERS]; - FVulkanSemaphore* RenderingCompletedSemaphore[VULKAN_NUM_IMAGE_BUFFERS]; - VulkanRHI::FFence* Fences[VULKAN_NUM_IMAGE_BUFFERS]; - uint32 CurrentFenceIndex; - - uint32 CurrentImageIndex; // Perhaps move this to the FVulkanSwapChain? -#endif VkQueue Queue; uint32 FamilyIndex; uint32 QueueIndex; diff --git a/Engine/Source/Runtime/VulkanRHI/Private/VulkanRHI.cpp b/Engine/Source/Runtime/VulkanRHI/Private/VulkanRHI.cpp index 44186a9ad105..06a6988655b2 100644 --- a/Engine/Source/Runtime/VulkanRHI/Private/VulkanRHI.cpp +++ b/Engine/Source/Runtime/VulkanRHI/Private/VulkanRHI.cpp @@ -13,8 +13,12 @@ #include "VulkanContext.h" #include "VulkanManager.h" +#ifdef VK_API_VERSION // Check the SDK is least the API version we want to use static_assert(VK_API_VERSION >= UE_VK_API_VERSION, "Vulkan SDK is older than the version we want to support (UE_VK_API_VERSION). Please update your SDK."); +#elif !defined(VK_HEADER_VERSION) + #error No VulkanSDK defines? +#endif #if VK_HEADER_VERSION < 8 && (VK_API_VERSION < VK_MAKE_VERSION(1, 0, 3)) #include @@ -26,6 +30,12 @@ static TAutoConsoleVariable GLSLCvar( TEXT("2 to use ES GLSL\n1 to use GLSL\n0 to use SPIRV") ); +static TAutoConsoleVariable GRHIThreadCvar( + TEXT("r.Vulkan.RHIThread"), + 0, + TEXT("1 to use RHI Thread") + ); + #if VULKAN_CUSTOM_MEMORY_MANAGER_ENABLED VkAllocationCallbacks GCallbacks; #endif @@ -199,10 +209,7 @@ FVulkanCommandListContext::FVulkanCommandListContext(FVulkanDynamicRHI* InRHI, F , PendingMinVertexIndex(0) , PendingIndexDataStride(0) , TempFrameAllocationBuffer(InDevice, VULKAN_TEMP_FRAME_ALLOCATOR_SIZE) -#if VULKAN_USE_NEW_COMMAND_BUFFERS -#else , CommandBufferManager(nullptr) -#endif { // Create CommandBufferManager, contain all active buffers CommandBufferManager = new FVulkanCommandBufferManager(InDevice); @@ -261,6 +268,8 @@ void FVulkanDynamicRHI::Shutdown() check(IsInGameThread() && IsInRenderingThread()); check(Device); + Device->PrepareForDestroy(); + EmptyCachedBoundShaderStates(); FVulkanVertexDeclaration::EmptyCache(); @@ -403,7 +412,12 @@ void FVulkanDynamicRHI::InitInstance() if (!Device) { check(!GIsRHIInitialized); - + +#ifdef PLATFORM_ANDROID + // Want to see the actual crash report on Android so unregister signal handlers + FPlatformMisc::SetCrashHandler((void(*)(const FGenericCrashContext& Context)) -1); +#endif + GRHISupportsAsyncTextureCreation = false; bool bDeviceSupportsGeometryShaders = true; @@ -448,11 +462,11 @@ void FVulkanDynamicRHI::InitInstance() GSupportsRenderTargetFormat_PF_G8 = false; // #todo-rco GSupportsQuads = false; // Not supported in Vulkan GRHISupportsTextureStreaming = false; // #todo-rco - GRHISupportsRHIThread = false; // #todo-rco + GRHISupportsRHIThread = GRHIThreadCvar->GetInt() != 0; // #todo-rco //#todo-rco: Leaks/issues still present! // Indicate that the RHI needs to use the engine's deferred deletion queue. - GRHINeedsExtraDeletionLatency = false; + GRHINeedsExtraDeletionLatency = true; GMaxShadowDepthBufferSizeX = FPlatformMath::Min(Props.limits.maxImageDimension2D, GMaxShadowDepthBufferSizeX); GMaxShadowDepthBufferSizeY = FPlatformMath::Min(Props.limits.maxImageDimension2D, GMaxShadowDepthBufferSizeY); @@ -532,14 +546,12 @@ void FVulkanCommandListContext::RHIBeginScene() void FVulkanCommandListContext::RHIEndScene() { -#if VULKAN_USE_NEW_COMMAND_BUFFERS auto* CmdBuffer = CommandBufferManager->GetActiveCmdBuffer(); auto& PendingState = Device->GetPendingState(); if (PendingState.IsRenderPassActive()) { PendingState.RenderPassEnd(CmdBuffer); } -#endif } void FVulkanCommandListContext::RHIBeginDrawingViewport(FViewportRHIParamRef ViewportRHI, FTextureRHIParamRef RenderTargetRHI) @@ -548,12 +560,7 @@ void FVulkanCommandListContext::RHIBeginDrawingViewport(FViewportRHIParamRef Vie FVulkanViewport* Viewport = ResourceCast(ViewportRHI); if (Viewport->GetBackBufferIndex() < 0) { -#if VULKAN_USE_NEW_COMMAND_BUFFERS Viewport->AcquireBackBuffer(Device->GetImmediateContext().GetCommandBufferManager()->GetActiveCmdBuffer()); -#else - // SMEDIS: This is the normal method of getting a new backbuffer. However, RHIGetViewportBackBuffer() can also do it if necessary. - Viewport->CurrentBackBuffer = Device->GetQueue()->AquireImageIndex(Viewport->SwapChain); -#endif } RHI->DrawingViewport = Viewport; @@ -592,9 +599,7 @@ void FVulkanCommandListContext::RHIEndDrawingViewport(FViewportRHIParamRef Viewp void FVulkanCommandListContext::RHIEndFrame() { -#if VULKAN_USE_NEW_COMMAND_BUFFERS Device->GetDeferredDeletionQueue().Clear(); -#endif Device->GetStagingManager().ProcessPendingFree(); Device->GetResourceHeapManager().ReleaseFreedPages(); @@ -613,12 +618,7 @@ void FVulkanCommandListContext::RHIPushEvent(const TCHAR* Name, FColor Color) #if VULKAN_ENABLE_DRAW_MARKERS if (auto VkCmdDbgMarkerBegin = Device->GetCmdDbgMarkerBegin()) { -#if VULKAN_USE_NEW_COMMAND_BUFFERS VkCmdDbgMarkerBegin(GetCommandBufferManager()->GetActiveCmdBuffer()->GetHandle(), TCHAR_TO_ANSI(Name)); -#else - FVulkanPendingState& State = Device->GetPendingState(); - VkCmdDbgMarkerBegin(State.GetCommandBuffer(), TCHAR_TO_ANSI(Name)); -#endif } #endif @@ -635,11 +635,7 @@ void FVulkanCommandListContext::RHIPopEvent() if (auto VkCmdDbgMarkerEnd = Device->GetCmdDbgMarkerEnd()) { FVulkanPendingState& State = Device->GetPendingState(); -#if VULKAN_USE_NEW_COMMAND_BUFFERS VkCmdDbgMarkerEnd(GetCommandBufferManager()->GetActiveCmdBuffer()->GetHandle()); -#else - VkCmdDbgMarkerEnd(State.GetCommandBuffer()); -#endif } #endif @@ -770,7 +766,7 @@ void FVulkanBuffer::Unlock() void FVulkanBuffer::CopyTo(FVulkanSurface& Surface, const VkBufferImageCopy& CopyDesc, FVulkanPendingState* State) { -#if VULKAN_USE_NEW_COMMAND_BUFFERS +#if 1//VULKAN_USE_NEW_COMMAND_BUFFERS check(0); #else VkCommandBuffer Cmd = VK_NULL_HANDLE; @@ -934,7 +930,7 @@ FVulkanDescriptorSets::~FVulkanDescriptorSets() } } -void FVulkanBufferView::Create(FVulkanDevice& Device, FVulkanBuffer& Buffer, EPixelFormat Format, uint32 Offset, uint32 Size) +void FVulkanBufferView::Create(FVulkanBuffer& Buffer, EPixelFormat Format, uint32 Offset, uint32 Size) { VkBufferViewCreateInfo ViewInfo; FMemory::Memzero(ViewInfo); @@ -952,10 +948,10 @@ void FVulkanBufferView::Create(FVulkanDevice& Device, FVulkanBuffer& Buffer, EPi Flags = Buffer.GetFlags() & VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT; check(Flags); - VERIFYVULKANRESULT(vkCreateBufferView(Device.GetInstanceHandle(), &ViewInfo, nullptr, &View)); + VERIFYVULKANRESULT(vkCreateBufferView(GetParent()->GetInstanceHandle(), &ViewInfo, nullptr, &View)); } -void FVulkanBufferView::Create(FVulkanDevice& Device, FVulkanResourceMultiBuffer* Buffer, EPixelFormat Format, uint32 Offset, uint32 Size) +void FVulkanBufferView::Create(FVulkanResourceMultiBuffer* Buffer, EPixelFormat Format, uint32 Offset, uint32 Size) { VkBufferViewCreateInfo ViewInfo; FMemory::Memzero(ViewInfo); @@ -975,14 +971,14 @@ void FVulkanBufferView::Create(FVulkanDevice& Device, FVulkanResourceMultiBuffer ViewInfo.flags = Flags; - VERIFYVULKANRESULT(vkCreateBufferView(Device.GetInstanceHandle(), &ViewInfo, nullptr, &View)); + VERIFYVULKANRESULT(vkCreateBufferView(GetParent()->GetInstanceHandle(), &ViewInfo, nullptr, &View)); } -void FVulkanBufferView::Destroy(FVulkanDevice& Device) +void FVulkanBufferView::Destroy() { if (View != VK_NULL_HANDLE) { - vkDestroyBufferView(Device.GetInstanceHandle(), View, nullptr); + vkDestroyBufferView(GetParent()->GetInstanceHandle(), View, nullptr); View = VK_NULL_HANDLE; } } @@ -1031,11 +1027,11 @@ FVulkanRenderTargetLayout::FVulkanRenderTargetLayout(const FRHISetRenderTargetsI #if !VULKAN_USE_MSAA_RESOLVE_ATTACHMENTS CurrDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; #endif - CurrDesc.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - CurrDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + CurrDesc.initialLayout = VK_IMAGE_LAYOUT_GENERAL; + CurrDesc.finalLayout = VK_IMAGE_LAYOUT_GENERAL; ColorReferences[NumColorAttachments].attachment = NumAttachments; - ColorReferences[NumColorAttachments].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + ColorReferences[NumColorAttachments].layout = VK_IMAGE_LAYOUT_GENERAL; NumAttachments++; #if VULKAN_USE_MSAA_RESOLVE_ATTACHMENTS @@ -1190,25 +1186,6 @@ FVulkanRenderPass::~FVulkanRenderPass() RenderPass = VK_NULL_HANDLE; } -#if VULKAN_USE_NEW_COMMAND_BUFFERS -#else -void FVulkanRenderPass::Begin(FVulkanCmdBuffer& CmdBuf, const VkFramebuffer& Framebuffer, const VkClearValue* AttachmentClearValues) -{ - VkRenderPassBeginInfo Info; - FMemory::Memzero(Info); - Info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - Info.renderPass = GetHandle(); - Info.framebuffer = Framebuffer; - Info.renderArea.offset.x = 0; - Info.renderArea.offset.y = 0; - Info.renderArea.extent = Layout.GetExtent2D(); - Info.clearValueCount = Layout.GetNumAttachments(); - Info.pClearValues = AttachmentClearValues; - - vkCmdBeginRenderPass(CmdBuf.GetHandle(false), &Info, VK_SUBPASS_CONTENTS_INLINE); -} -#endif - void VulkanSetImageLayout( VkCommandBuffer CmdBuffer, @@ -1232,7 +1209,7 @@ void VulkanSetImageLayout( switch (NewLayout) { case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: - ImageBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + ImageBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; break; case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: ImageBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; @@ -1241,6 +1218,10 @@ void VulkanSetImageLayout( ImageBarrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; break; case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: + if (OldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) + { + ImageBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + } ImageBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_INPUT_ATTACHMENT_READ_BIT; break; case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR: @@ -1310,17 +1291,13 @@ FVulkanRingBuffer::FVulkanRingBuffer(FVulkanDevice* InDevice, uint64 TotalSize, , MinAlignment(0) { FRHIResourceCreateInfo CreateInfo; - Buffer = InDevice->GetStagingManager().AcquireBuffer(TotalSize, Usage); - - VkMemoryRequirements MemReqs; - vkGetBufferMemoryRequirements(InDevice->GetInstanceHandle(), Buffer->GetHandle(), &MemReqs); - - MinAlignment = (uint32)MemReqs.alignment; + BufferSuballocation = InDevice->GetResourceHeapManager().AllocateBuffer(TotalSize, Usage, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, __FILE__, __LINE__); + MinAlignment = BufferSuballocation->GetBufferAllocation()->GetAlignment(); } FVulkanRingBuffer::~FVulkanRingBuffer() { - Device->GetStagingManager().ReleaseBuffer(Buffer); + delete BufferSuballocation; } uint64 FVulkanRingBuffer::AllocateMemory(uint64 Size, uint32 Alignment) @@ -1363,5 +1340,6 @@ void FVulkanDynamicRHI::DumpMemory() auto* RHI = (FVulkanDynamicRHI*)GDynamicRHI; RHI->Device->GetMemoryManager().DumpMemory(); RHI->Device->GetResourceHeapManager().DumpMemory(); + RHI->Device->GetStagingManager().DumpMemory(); } #endif diff --git a/Engine/Source/Runtime/VulkanRHI/Private/VulkanRHIPrivate.h b/Engine/Source/Runtime/VulkanRHI/Private/VulkanRHIPrivate.h index b5bf1e16ffb7..81ada820703d 100644 --- a/Engine/Source/Runtime/VulkanRHI/Private/VulkanRHIPrivate.h +++ b/Engine/Source/Runtime/VulkanRHI/Private/VulkanRHIPrivate.h @@ -185,11 +185,7 @@ public: TArray Attachments; TArray SubresourceRanges; -#if VULKAN_USE_NEW_COMMAND_BUFFERS - void InsertWriteBarrier(FVulkanCmdBuffer* CmdBuffer); -#else - void InsertWriteBarrier(VkCommandBuffer cmd); -#endif + void InsertWriteBarriers(FVulkanCmdBuffer* CmdBuffer); private: VkFramebuffer Framebuffer; @@ -219,15 +215,6 @@ private: FVulkanRenderPass(FVulkanDevice& Device, const FVulkanRenderTargetLayout& RTLayout); ~FVulkanRenderPass(); -#if VULKAN_USE_NEW_COMMAND_BUFFERS -#else - void Begin(FVulkanCmdBuffer& CmdBuf, const VkFramebuffer& Framebuffer, const VkClearValue* AttachmentClearValues); - void End(FVulkanCmdBuffer& CmdBuf) - { - vkCmdEndRenderPass(CmdBuf.GetHandle()); - } -#endif - private: FVulkanRenderTargetLayout Layout; VkRenderPass RenderPass; @@ -328,6 +315,9 @@ private: FVulkanDescriptorPool* Pool; const FVulkanDescriptorSetsLayout& Layout; TArray Sets; + + friend class FVulkanBoundShaderState; + friend class FVulkanCommandListContext; }; void VulkanSetImageLayout(VkCommandBuffer CmdBuffer, VkImage Image, VkImageLayout OldLayout, VkImageLayout NewLayout, const VkImageSubresourceRange& SubresourceRange); diff --git a/Engine/Source/Runtime/VulkanRHI/Private/VulkanRenderTarget.cpp b/Engine/Source/Runtime/VulkanRHI/Private/VulkanRenderTarget.cpp index 0c4da72ea727..18c98ced8126 100644 --- a/Engine/Source/Runtime/VulkanRHI/Private/VulkanRenderTarget.cpp +++ b/Engine/Source/Runtime/VulkanRHI/Private/VulkanRenderTarget.cpp @@ -37,16 +37,8 @@ void FVulkanCommandListContext::RHISetRenderTargetsAndClear(const FRHISetRenderT FVulkanPendingState& PendingState = Device->GetPendingState(); PendingState.SetRenderTargetsInfo(RenderTargetsInfo); -#if VULKAN_USE_NEW_COMMAND_BUFFERS - auto* CmdBuffer = CommandBufferManager->GetActiveCmdBuffer(); - //#todo-rco: Write barrier always for now... - FVulkanFramebuffer* Framebuffer = PendingState.GetFrameBuffer(); - if (Framebuffer) - { - Framebuffer->InsertWriteBarrier(CmdBuffer); - } - #if 0//VULKAN_USE_NEW_RESOURCE_MANAGEMENT + auto* CmdBuffer = CommandBufferManager->GetActiveCmdBuffer(); if (CmdBuffer->IsInsideRenderPass()) { if ( @@ -58,15 +50,13 @@ void FVulkanCommandListContext::RHISetRenderTargetsAndClear(const FRHISetRenderT } } #endif -#else -#endif } void FVulkanCommandListContext::RHICopyToResolveTarget(FTextureRHIParamRef SourceTextureRHI, FTextureRHIParamRef DestTextureRHI, bool bKeepOriginalSurface, const FResolveParams& ResolveParams) { FVulkanPendingState& State = Device->GetPendingState(); -#if VULKAN_USE_NEW_COMMAND_BUFFERS +#if 1//VULKAN_USE_NEW_COMMAND_BUFFERS auto* CmdBuffer = CommandBufferManager->GetActiveCmdBuffer(); // Verify if we need to do some work (for the case of SetRT(), CopyToResolve() with no draw calls in between) State.UpdateRenderPass(CmdBuffer); @@ -78,7 +68,14 @@ void FVulkanCommandListContext::RHICopyToResolveTarget(FTextureRHIParamRef Sourc State.RenderPassEnd(CmdBuffer); } - check(SourceTextureRHI->GetNumSamples() < 2); + check(!SourceTextureRHI || SourceTextureRHI->GetNumSamples() < 2); + + FVulkanFramebuffer* Framebuffer = State.GetFrameBuffer(); + if (Framebuffer) + { + Framebuffer->InsertWriteBarriers(GetCommandBufferManager()->GetActiveCmdBuffer()); + } + #else // If we're using the pResolveAttachments property of the subpass, so we don't need manual command buffer resolves and this function is a NoOp. #if !VULKAN_USE_MSAA_RESOLVE_ATTACHMENTS @@ -160,7 +157,7 @@ void FVulkanCommandListContext::RHITransitionResources(EResourceTransitionAccess FVulkanTexture2D* Texture = (FVulkanTexture2D*)RHITexture2D; if (Texture->Surface.ImageLayout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) { -#if VULKAN_USE_NEW_COMMAND_BUFFERS +#if 1//VULKAN_USE_NEW_COMMAND_BUFFERS check(0); #else check(Texture->Surface.GetAspectMask() == VK_IMAGE_ASPECT_COLOR_BIT); diff --git a/Engine/Source/Runtime/VulkanRHI/Private/VulkanShaders.cpp b/Engine/Source/Runtime/VulkanRHI/Private/VulkanShaders.cpp index 852cb20a06c4..ae5bc237a90c 100644 --- a/Engine/Source/Runtime/VulkanRHI/Private/VulkanShaders.cpp +++ b/Engine/Source/Runtime/VulkanRHI/Private/VulkanShaders.cpp @@ -225,7 +225,6 @@ FVulkanBoundShaderState::FVulkanBoundShaderState( , BindingsNum(0) , BindingsMask(0) , AttributesNum(0) - , LastFrameRendered(-1) #if VULKAN_ENABLE_PIPELINE_CACHE , GlobalListLink(this) #endif @@ -243,7 +242,6 @@ FVulkanBoundShaderState::FVulkanBoundShaderState( FMemory::Memzero(DirtyPackedUniformBufferStagingMask); FMemory::Memzero(DescriptorBufferInfoForStage); FMemory::Memzero(SRVWriteInfoForStage); - FMemory::Memzero(CurrentDS); #if VULKAN_HAS_DEBUGGING_ENABLED FMemory::Memzero(ImageDescCount); @@ -251,13 +249,6 @@ FVulkanBoundShaderState::FVulkanBoundShaderState( check(Device); -#if VULKAN_USE_NEW_COMMAND_BUFFERS - //#todo-rco: Fix this! - LastFrameRendered = GFrameNumberRenderThread; -#else - LastFrameRendered = Device->GetPendingState().GetCurrentCommandBufferIndex(); -#endif - Layout = new FVulkanDescriptorSetsLayout(Device); FVulkanVertexDeclaration* InVertexDeclaration = ResourceCast(InVertexDeclarationRHI); @@ -333,15 +324,11 @@ FVulkanBoundShaderState::~FVulkanBoundShaderState() GlobalListLink.Unlink(); #endif - // Nuke descriptor sets - for(uint32 CommandIndex=0; CommandIndex& Sets = DescriptorSets[CommandIndex]; - for(FVulkanDescriptorSets* DescriptorSet : Sets) - { - Device->GetPendingState().DeallocateDescriptorSet(DescriptorSet, this); - } + delete DescriptorSetsEntries[Index]; } + DescriptorSetsEntries.Empty(0); // toss the pipeline states for (auto& Pair : PipelineCache) @@ -396,7 +383,9 @@ FVulkanPipeline* FVulkanBoundShaderState::PrepareForDraw(const FVulkanPipelineGr #if !UE_BUILD_SHIPPING if (Device->FrameCounter > 3) { - FPlatformMisc::LowLevelOutputDebugStringf(TEXT("Created a hitchy pipeline state for hash %llx %x (this = %p) VS %s %p %d PS %s %p %d\n"), PipelineKey, VertexInputKey, this, *VertexShader->DebugName, (void*)VertexShader.GetReference(), VertexShader->GlslSource.Num(), *PixelShader->DebugName, (void*)PixelShader.GetReference(), PixelShader->GlslSource.Num()); + FPlatformMisc::LowLevelOutputDebugStringf(TEXT("Created a hitchy pipeline state for hash %llx%llx %x (this = %x) VS %s %x %d PS %s %x %d\n"), + PipelineKey.Key[0], PipelineKey.Key[1], VertexInputKey, this, *VertexShader->DebugName, (void*)VertexShader.GetReference(), VertexShader->GlslSource.Num(), + *PixelShader->DebugName, (void*)PixelShader.GetReference(), PixelShader->GlslSource.Num()); } #endif } @@ -423,18 +412,6 @@ void FVulkanBoundShaderState::ResetState() CurrDescriptorSets = nullptr; -#if VULKAN_USE_NEW_COMMAND_BUFFERS - //#todo-rco: Fix this! - const uint32 CurrentImageIndex = GFrameNumberRenderThread % ARRAY_COUNT(CurrentDS); -#else - // reset the DS list the first time it's used in a frame - const uint32 CurrentImageIndex = Device->GetPendingState().GetCurrentCommandBufferIndex(); -#endif - if (LastFrameRendered != CurrentImageIndex) - { - CurrentDS[CurrentImageIndex] = 0; - LastFrameRendered = CurrentImageIndex; - } LastBoundPipeline = VK_NULL_HANDLE; bDirtyVertexStreams = true; } @@ -1053,7 +1030,48 @@ void FVulkanBoundShaderState::SetLastError(const FString& Error) } #endif -void FVulkanBoundShaderState::UpdateDescriptorSets(FVulkanGlobalUniformPool* GlobalUniformPool) +FVulkanBoundShaderState::FDescriptorSetsPair::~FDescriptorSetsPair() +{ + delete DescriptorSets; +} + +inline FVulkanDescriptorSets* FVulkanBoundShaderState::RequestDescriptorSets(FVulkanCmdBuffer* CmdBuffer) +{ + //#todo-rco: Make thread safe! + FDescriptorSetsEntry* FoundEntry = nullptr; + for (FDescriptorSetsEntry* DescriptorSetsEntry : DescriptorSetsEntries) + { + if (DescriptorSetsEntry->CmdBuffer == CmdBuffer) + { + FoundEntry = DescriptorSetsEntry; + } + } + + if (!FoundEntry) + { + FoundEntry = new FDescriptorSetsEntry(CmdBuffer); + DescriptorSetsEntries.Add(FoundEntry); + } + + const uint64 CmdBufferFenceSignaledCounter = CmdBuffer->GetFenceSignaledCounter(); + for (int32 Index = 0; Index < FoundEntry->Pairs.Num(); ++Index) + { + FDescriptorSetsPair& Entry = FoundEntry->Pairs[Index]; + if (Entry.FenceCounter < CmdBufferFenceSignaledCounter) + { + Entry.FenceCounter = CmdBufferFenceSignaledCounter; + return Entry.DescriptorSets; + } + } + + FDescriptorSetsPair* NewEntry = new (FoundEntry->Pairs) FDescriptorSetsPair; + NewEntry->DescriptorSets = new FVulkanDescriptorSets(Device, this, Device->GetDescriptorPool()); + NewEntry->FenceCounter = CmdBufferFenceSignaledCounter; + return NewEntry->DescriptorSets; +} + + +void FVulkanBoundShaderState::UpdateDescriptorSets(FVulkanCommandListContext* CmdListContext, FVulkanCmdBuffer* CmdBuffer, FVulkanGlobalUniformPool* GlobalUniformPool) { #if VULKAN_ENABLE_AGGRESSIVE_STATS SCOPE_CYCLE_COUNTER(STAT_VulkanUpdateDescriptorSets); @@ -1065,24 +1083,7 @@ void FVulkanBoundShaderState::UpdateDescriptorSets(FVulkanGlobalUniformPool* Glo int32 WriteIndex = 0; - // get the next available DS - -#if VULKAN_USE_NEW_COMMAND_BUFFERS - //#todo-rco: Fix this! - const uint32 CurrentImageIndex = GFrameNumberRenderThread % ARRAY_COUNT(CurrentDS); -#else - // This is the image where we are going to execute command buffer into - const uint32 CurrentImageIndex = Device->GetPendingState().GetCurrentCommandBufferIndex(); -#endif - TArray& CurrentDescriptorSet = DescriptorSets[CurrentImageIndex]; - int32& CurrentDescriptorSetIndex = CurrentDS[CurrentImageIndex]; - - if (CurrentDescriptorSetIndex == CurrentDescriptorSet.Num()) - { - // @todo vulkan: we need to check we don't make more of these than MaxSets in FVulkanPendingState constructor!! - CurrentDescriptorSet.Push(State.AllocateDescriptorSet(this)); - } - CurrDescriptorSets = CurrentDescriptorSet[CurrentDescriptorSetIndex++]; + CurrDescriptorSets = RequestDescriptorSets(CmdBuffer); auto& DescriptorSetHandles = CurrDescriptorSets->GetHandles(); int32 DescriptorSetIndex = 0; @@ -1090,7 +1091,7 @@ void FVulkanBoundShaderState::UpdateDescriptorSets(FVulkanGlobalUniformPool* Glo #if VULKAN_USE_RING_BUFFER_FOR_GLOBAL_UBS // this is an optimization for the ring buffer to only truly lock once for all uniforms FVulkanRingBuffer* RingBuffer = Device->GetUBRingBuffer(); - uint8* RingBufferBase = (uint8*)RingBuffer->Buffer->GetMappedPointer(); + uint8* RingBufferBase = (uint8*)RingBuffer->GetMappedPointer(); #endif //#todo-rco: Compute! @@ -1156,8 +1157,8 @@ void FVulkanBoundShaderState::UpdateDescriptorSets(FVulkanGlobalUniformPool* Glo // Here we can specify a more precise buffer update // However, this need to complemented with the buffer map/unmap functionality. //@NOTE: bufferView is for texel buffers - BufferInfo->buffer = RingBuffer->Buffer->GetHandle(); - BufferInfo->offset = RingBufferOffset; + BufferInfo->buffer = RingBuffer->GetHandle(); + BufferInfo->offset = RingBufferOffset + RingBuffer->GetBufferOffset(); BufferInfo->range = UBSize; #else diff --git a/Engine/Source/Runtime/VulkanRHI/Private/VulkanSwapChain.cpp b/Engine/Source/Runtime/VulkanRHI/Private/VulkanSwapChain.cpp index b5723ab99305..a85069efb8ce 100644 --- a/Engine/Source/Runtime/VulkanRHI/Private/VulkanSwapChain.cpp +++ b/Engine/Source/Runtime/VulkanRHI/Private/VulkanSwapChain.cpp @@ -12,9 +12,8 @@ FVulkanSwapChain::FVulkanSwapChain(VkInstance Instance, FVulkanDevice& InDevice, : SwapChain(VK_NULL_HANDLE) , Device(InDevice) , Surface(VK_NULL_HANDLE) -#if VULKAN_USE_NEW_COMMAND_BUFFERS , CurrentImageIndex(-1) -#endif + , SemaphoreIndex(0) { #define FETCH_KHR_FPN(FunctionPointerName)\ {\ @@ -197,34 +196,31 @@ FVulkanSwapChain::FVulkanSwapChain(VkInstance Instance, FVulkanDevice& InDevice, OutImages.AddUninitialized(NumSwapChainImages); VERIFYVULKANRESULT_EXPANDED(GetSwapchainImagesKHR(Device.GetInstanceHandle(), SwapChain, &NumSwapChainImages, OutImages.GetData())); -#if VULKAN_USE_NEW_COMMAND_BUFFERS ImageAcquiredSemaphore.AddUninitialized(DesiredNumBuffers); - RenderingCompletedSemaphore.AddUninitialized(DesiredNumBuffers); + //RenderingCompletedSemaphore.AddUninitialized(DesiredNumBuffers); for (uint32 BufferIndex = 0; BufferIndex < DesiredNumBuffers; ++BufferIndex) { ImageAcquiredSemaphore[BufferIndex] = new FVulkanSemaphore(Device); - RenderingCompletedSemaphore[BufferIndex] = new FVulkanSemaphore(Device); + //RenderingCompletedSemaphore[BufferIndex] = new FVulkanSemaphore(Device); } -#endif } void FVulkanSwapChain::Destroy() { -#if VULKAN_USE_NEW_COMMAND_BUFFERS + vkDestroySwapchainKHR(Device.GetInstanceHandle(), SwapChain, nullptr); + SwapChain = VK_NULL_HANDLE; + + //#todo-rco: Enqueue for deletion as we first need to destroy the cmd buffers and queues otherwise validation fails for (int BufferIndex = 0; BufferIndex < ImageAcquiredSemaphore.Num(); ++BufferIndex) { delete ImageAcquiredSemaphore[BufferIndex]; - delete RenderingCompletedSemaphore[BufferIndex]; + //delete RenderingCompletedSemaphore[BufferIndex]; } ImageAcquiredSemaphore.Empty(0); - RenderingCompletedSemaphore.Empty(0); -#endif - vkDestroySwapchainKHR(Device.GetInstanceHandle(), SwapChain, nullptr); - SwapChain = VK_NULL_HANDLE; + //RenderingCompletedSemaphore.Empty(0); } -#if VULKAN_USE_NEW_COMMAND_BUFFERS -int32 FVulkanSwapChain::AcquireImageIndex() +int32 FVulkanSwapChain::AcquireImageIndex(FVulkanSemaphore** OutSemaphore) { // Get the index of the next swapchain image we should render to. // We'll wait with an "infinite" timeout, the function will block until an image is ready. @@ -233,15 +229,18 @@ int32 FVulkanSwapChain::AcquireImageIndex() // Note: Queues can still be filled in on the CPU side, but won't execute until the semaphore is signaled. //CurrentImageIndex = -1; uint32 ImageIndex = 0; + SemaphoreIndex = (SemaphoreIndex + 1) % ImageAcquiredSemaphore.Num(); + *OutSemaphore = ImageAcquiredSemaphore[SemaphoreIndex]; VkResult Result = AcquireNextImageKHR( Device.GetInstanceHandle(), SwapChain, UINT64_MAX, - VK_NULL_HANDLE, //ImageAcquiredSemaphore[CurrentFenceIndex]->GetHandle(), + ImageAcquiredSemaphore[SemaphoreIndex]->GetHandle(), VK_NULL_HANDLE, &ImageIndex); checkf(Result == VK_SUCCESS || Result == VK_SUBOPTIMAL_KHR, TEXT("AcquireNextImageKHR failed Result = %d"), int32(Result)); CurrentImageIndex = (int32)ImageIndex; + check(CurrentImageIndex == ImageIndex); return CurrentImageIndex; } @@ -252,17 +251,12 @@ void FVulkanSwapChain::Present(FVulkanQueue* Queue) VkPresentInfoKHR Info; FMemory::Memzero(Info); Info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; -/* - Info.waitSemaphoreCount = 1; // 0; // 1; - VkSemaphore Semaphore = RenderingCompletedSemaphore[CurrentImageIndex]->GetHandle(); + Info.waitSemaphoreCount = 1; + VkSemaphore Semaphore = ImageAcquiredSemaphore[SemaphoreIndex]->GetHandle(); Info.pWaitSemaphores = &Semaphore; -*/ - Info.swapchainCount = 1; Info.pSwapchains = &SwapChain; Info.pImageIndices = (uint32*)&CurrentImageIndex; VERIFYVULKANRESULT(QueuePresentKHR(Queue->GetHandle(), &Info)); } -#else -#endif diff --git a/Engine/Source/Runtime/VulkanRHI/Private/VulkanSwapChain.h b/Engine/Source/Runtime/VulkanRHI/Private/VulkanSwapChain.h index 94de95f4cffb..dc62945130e3 100644 --- a/Engine/Source/Runtime/VulkanRHI/Private/VulkanSwapChain.h +++ b/Engine/Source/Runtime/VulkanRHI/Private/VulkanSwapChain.h @@ -11,23 +11,12 @@ class FVulkanQueue; class FVulkanSwapChain { public: -#if VULKAN_USE_NEW_COMMAND_BUFFERS -#else -#if !PLATFORM_WINDOWS - //@HACK : maybe NUM_BUFFERS at VulkanViewport should be moved to here? - enum { NUM_BUFFERS = 2 }; -#endif -#endif - FVulkanSwapChain(VkInstance Instance, FVulkanDevice& InDevice, void* WindowHandle, EPixelFormat& InOutPixelFormat, uint32 Width, uint32 Height, uint32* InOutDesiredNumBackBuffers, TArray& OutImages); void Destroy(); -#if VULKAN_USE_NEW_COMMAND_BUFFERS void Present(FVulkanQueue* Queue); -#else -#endif protected: VkSwapchainKHR SwapChain; @@ -41,17 +30,13 @@ protected: VkSurfaceKHR Surface; -#if VULKAN_USE_NEW_COMMAND_BUFFERS int32 CurrentImageIndex; + int32 SemaphoreIndex; TArray ImageAcquiredSemaphore; - TArray RenderingCompletedSemaphore; -#else -#endif + //TArray RenderingCompletedSemaphore; -#if VULKAN_USE_NEW_COMMAND_BUFFERS - int32 AcquireImageIndex(); + int32 AcquireImageIndex(FVulkanSemaphore** OutSemaphore); friend class FVulkanViewport; -#else -#endif + friend class FVulkanQueue; }; diff --git a/Engine/Source/Runtime/VulkanRHI/Private/VulkanTexture.cpp b/Engine/Source/Runtime/VulkanRHI/Private/VulkanTexture.cpp index e276f2f67156..0aa10c88d13e 100644 --- a/Engine/Source/Runtime/VulkanRHI/Private/VulkanTexture.cpp +++ b/Engine/Source/Runtime/VulkanRHI/Private/VulkanTexture.cpp @@ -77,7 +77,7 @@ VkImage FVulkanSurface::CreateImage( } ImageCreateInfo.format = (VkFormat)GPixelFormats[InFormat].PlatformFormat; - if ((UEFlags & TexCreate_SRGB) == TexCreate_SRGB) + if ((UEFlags & TexCreate_SRGB) == TexCreate_SRGB && GMaxRHIFeatureLevel > ERHIFeatureLevel::ES3_1) { switch (ImageCreateInfo.format) { @@ -178,26 +178,32 @@ VkImage FVulkanSurface::CreateImage( break; } +//#todo-rco: Verify flags work on newer Android drivers +#if !PLATFORM_ANDROID if (ImageCreateInfo.tiling == VK_IMAGE_TILING_LINEAR) { VkFormatFeatureFlags FormatFlags = InDevice.GetFormatProperties()[ImageCreateInfo.format].linearTilingFeatures; if ((FormatFlags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) == 0) { + ensure((ImageCreateInfo.usage & VK_IMAGE_USAGE_SAMPLED_BIT) == 0); ImageCreateInfo.usage &= ~VK_IMAGE_USAGE_SAMPLED_BIT; } if ((FormatFlags & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT) == 0) { + ensure((ImageCreateInfo.usage & VK_IMAGE_USAGE_STORAGE_BIT) == 0); ImageCreateInfo.usage &= ~VK_IMAGE_USAGE_STORAGE_BIT; } if ((FormatFlags & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) == 0) { + ensure((ImageCreateInfo.usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) == 0); ImageCreateInfo.usage &= ~VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; } if ((FormatFlags & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) == 0) { + ensure((ImageCreateInfo.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) == 0); ImageCreateInfo.usage &= ~VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; } } @@ -206,24 +212,29 @@ VkImage FVulkanSurface::CreateImage( VkFormatFeatureFlags FormatFlags = InDevice.GetFormatProperties()[ImageCreateInfo.format].optimalTilingFeatures; if ((FormatFlags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) == 0) { + ensure((ImageCreateInfo.usage & VK_IMAGE_USAGE_SAMPLED_BIT) == 0); ImageCreateInfo.usage &= ~VK_IMAGE_USAGE_SAMPLED_BIT; } if ((FormatFlags & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT) == 0) { + ensure((ImageCreateInfo.usage & VK_IMAGE_USAGE_STORAGE_BIT) == 0); ImageCreateInfo.usage &= ~VK_IMAGE_USAGE_STORAGE_BIT; } if ((FormatFlags & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) == 0) { + ensure((ImageCreateInfo.usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) == 0); ImageCreateInfo.usage &= ~VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; } if ((FormatFlags & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) == 0) { + ensure((ImageCreateInfo.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) == 0); ImageCreateInfo.usage &= ~VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; } } +#endif VkImage Image; VERIFYVULKANRESULT(vkCreateImage(InDevice.GetInstanceHandle(), &ImageCreateInfo, nullptr, &Image)); @@ -320,11 +331,7 @@ FVulkanSurface::FVulkanSurface(FVulkanDevice& InDevice, VkImageViewType Resource if ((ImageCreateInfo.usage & VK_IMAGE_USAGE_SAMPLED_BIT) && (UEFlags & (TexCreate_RenderTargetable | TexCreate_DepthStencilTargetable))) { const bool bTransitionToPresentable = ((UEFlags & TexCreate_Presentable) == TexCreate_Presentable); -#if VULKAN_USE_NEW_COMMAND_BUFFERS Clear(CreateInfo.ClearValueBinding, bTransitionToPresentable); -#else - ClearBlocking(CreateInfo.ClearValueBinding, bTransitionToPresentable); -#endif } } @@ -354,7 +361,7 @@ FVulkanSurface::FVulkanSurface(FVulkanDevice& InDevice, VkImageViewType Resource AspectMask = GetAspectMask(InternalFormat); // Purely informative patching, we know that "TexCreate_Presentable" uses optimal tiling - if (UEFlags & TexCreate_Presentable && GetTiling() == VK_IMAGE_TILING_MAX_ENUM) + if ((UEFlags & TexCreate_Presentable) == TexCreate_Presentable && GetTiling() == VK_IMAGE_TILING_MAX_ENUM) { Tiling = VK_IMAGE_TILING_OPTIMAL; } @@ -364,11 +371,7 @@ FVulkanSurface::FVulkanSurface(FVulkanDevice& InDevice, VkImageViewType Resource if (UEFlags & (TexCreate_RenderTargetable | TexCreate_DepthStencilTargetable)) { const bool bTransitionToPresentable = ((UEFlags & TexCreate_Presentable) == TexCreate_Presentable); -#if VULKAN_USE_NEW_COMMAND_BUFFERS Clear(CreateInfo.ClearValueBinding, bTransitionToPresentable); -#else - ClearBlocking(CreateInfo.ClearValueBinding, bTransitionToPresentable); -#endif } } } @@ -607,7 +610,6 @@ VkImageAspectFlags FVulkanSurface::GetAspectMask() const return AspectMask; } -#if VULKAN_USE_NEW_COMMAND_BUFFERS void FVulkanSurface::Clear(const FClearValueBinding& ClearValueBinding, bool bTransitionToPresentable) { #if VULKAN_CLEAR_SURFACE_ON_CREATE @@ -619,14 +621,10 @@ void FVulkanSurface::Clear(const FClearValueBinding& ClearValueBinding, bool bTr Range.baseArrayLayer = 0; Range.layerCount = ViewType == VK_IMAGE_VIEW_TYPE_CUBE ? 6 : 1; -#if VULKAN_USE_NEW_COMMAND_BUFFERS - FVulkanCmdBuffer* CmdBuffer = Device->GetImmediateContext().GetCommandBufferManager()->GetActiveCmdBuffer(); + //#todo-rco: This function is only used during loading currently, if used for regular RHIClear then use the ActiveCmdBuffer + FVulkanCmdBuffer* CmdBuffer = Device->GetImmediateContext().GetCommandBufferManager()->GetUploadCmdBuffer(); ensure(CmdBuffer->IsOutsideRenderPass()); -#else - //#todo-rco: FIX ME! - FVulkanCmdBuffer* CmdBuffer = Device->GetImmediateContext().GetCommandBufferManager()->Create(); - CmdBuffer->Begin(); -#endif + if(Range.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT) { VkClearColorValue Color; @@ -653,61 +651,8 @@ void FVulkanSurface::Clear(const FClearValueBinding& ClearValueBinding, bool bTr VulkanSetImageLayoutSimple(CmdBuffer->GetHandle(), Image, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, Range.aspectMask); ImageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; } - -#if VULKAN_USE_NEW_COMMAND_BUFFERS -#else - Device->EndCommandBufferBlock(CmdBuffer); -#endif #endif } -#else -void FVulkanSurface::ClearBlocking(const FClearValueBinding& ClearValueBinding, bool bTransitionToPresentable) -{ -#if VULKAN_CLEAR_SURFACE_ON_CREATE - VkImageSubresourceRange Range; - FMemory::Memzero(Range); - Range.aspectMask = GetAspectMask(); - Range.baseMipLevel = 0; - Range.levelCount = NumMips; - Range.baseArrayLayer = 0; - Range.layerCount = ViewType == VK_IMAGE_VIEW_TYPE_CUBE ? 6 : 1; - - //#todo-rco: FIX ME! - FVulkanCmdBuffer* Cmd = Device->GetImmediateContext().GetCommandBufferManager()->Create(); - Cmd->Begin(); - - if(Range.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT) - { - VkClearColorValue Color; - FMemory::Memzero(Color); - Color.float32[0] = ClearValueBinding.Value.Color[0]; - Color.float32[1] = ClearValueBinding.Value.Color[1]; - Color.float32[2] = ClearValueBinding.Value.Color[2]; - Color.float32[3] = ClearValueBinding.Value.Color[3]; - VulkanSetImageLayoutSimple(Cmd->GetHandle(), Image, ImageLayout, VK_IMAGE_LAYOUT_GENERAL); - vkCmdClearColorImage(Cmd->GetHandle(), Image, VK_IMAGE_LAYOUT_GENERAL, &Color, 1, &Range); - ImageLayout = bTransitionToPresentable ? VK_IMAGE_LAYOUT_PRESENT_SRC_KHR : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - VulkanSetImageLayoutSimple(Cmd->GetHandle(), Image, VK_IMAGE_LAYOUT_GENERAL, ImageLayout); - } - else - { - check(Range.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)); - check(!bTransitionToPresentable); - VkClearDepthStencilValue Value; - FMemory::Memzero(Value); - Value.depth = ClearValueBinding.Value.DSValue.Depth; - Value.stencil = ClearValueBinding.Value.DSValue.Stencil; - VulkanSetImageLayoutSimple(Cmd->GetHandle(), Image, ImageLayout, VK_IMAGE_LAYOUT_GENERAL, Range.aspectMask); - vkCmdClearDepthStencilImage(Cmd->GetHandle(), Image, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, &Value, 1, &Range); - VulkanSetImageLayoutSimple(Cmd->GetHandle(), Image, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, Range.aspectMask); - ImageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - } - - Device->EndCommandBufferBlock(Cmd); -#endif -} -#endif - /*----------------------------------------------------------------------------- Texture allocator support. @@ -847,25 +792,10 @@ void FVulkanDynamicRHI::RHIUnlockTexture2D(FTexture2DRHIParamRef TextureRHI,uint checkf(bFound, TEXT("Texture was not locked!")); } -#if VULKAN_USE_NEW_COMMAND_BUFFERS - FVulkanCmdBuffer* CmdBuffer = Device->GetImmediateContext().GetCommandBufferManager()->GetActiveCmdBuffer(); + FVulkanCmdBuffer* CmdBuffer = Device->GetImmediateContext().GetCommandBufferManager()->GetUploadCmdBuffer(); ensure(CmdBuffer->IsOutsideRenderPass()); VkCommandBuffer StagingCommandBuffer = CmdBuffer->GetHandle(); -#else - VkCommandBuffer StagingCommandBuffer; - VkCommandBufferAllocateInfo CmdBufferCreateInfo; - FMemory::Memzero(CmdBufferCreateInfo); - CmdBufferCreateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - CmdBufferCreateInfo.commandPool = Device->GetImmediateContext().GetCommandBufferManager()->GetHandle(); - CmdBufferCreateInfo.commandBufferCount = 1; - CmdBufferCreateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - VERIFYVULKANRESULT(vkAllocateCommandBuffers(LogicalDevice, &CmdBufferCreateInfo, &StagingCommandBuffer)); - VkCommandBufferBeginInfo BufferBeginInfo; - FMemory::Memzero(BufferBeginInfo); - BufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - VERIFYVULKANRESULT(vkBeginCommandBuffer(StagingCommandBuffer, &BufferBeginInfo)); -#endif EPixelFormat Format = Texture->Surface.Format; uint32 MipWidth = FMath::Max(Texture->Surface.Width >> MipIndex, GPixelFormats[Format].BlockSizeX); uint32 MipHeight = FMath::Max(Texture->Surface.Height >> MipIndex, GPixelFormats[Format].BlockSizeY); @@ -877,7 +807,7 @@ void FVulkanDynamicRHI::RHIUnlockTexture2D(FTexture2DRHIParamRef TextureRHI,uint SubresourceRange.levelCount = 1; //SubresourceRange.baseArrayLayer = 0; SubresourceRange.layerCount = 1; - VulkanSetImageLayout(StagingCommandBuffer, Texture->Surface.Image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, SubresourceRange); + VulkanSetImageLayout(StagingCommandBuffer, Texture->Surface.Image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, SubresourceRange); VkBufferImageCopy Region; FMemory::Memzero(Region); @@ -892,28 +822,11 @@ void FVulkanDynamicRHI::RHIUnlockTexture2D(FTexture2DRHIParamRef TextureRHI,uint Region.imageExtent.width = MipWidth; Region.imageExtent.height = MipHeight; Region.imageExtent.depth = 1; - vkCmdCopyBufferToImage(StagingCommandBuffer, StagingBuffer->GetHandle(), Texture->Surface.Image, VK_IMAGE_LAYOUT_GENERAL, 1, &Region); + vkCmdCopyBufferToImage(StagingCommandBuffer, StagingBuffer->GetHandle(), Texture->Surface.Image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &Region); - VulkanSetImageLayout(StagingCommandBuffer, Texture->Surface.Image, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, SubresourceRange); + VulkanSetImageLayout(StagingCommandBuffer, Texture->Surface.Image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, SubresourceRange); -#if VULKAN_USE_NEW_COMMAND_BUFFERS Device->GetStagingManager().ReleaseBuffer(CmdBuffer, StagingBuffer); -#else - VERIFYVULKANRESULT(vkEndCommandBuffer(StagingCommandBuffer)); - - auto* Fence = Device->GetFenceManager().AllocateFence(); - Device->GetQueue()->Submit2(StagingCommandBuffer, Fence); - - bool bSuccess = Device->GetFenceManager().WaitForFence(Fence, 0xFFFFFFFF); - check(bSuccess); - - Device->GetFenceManager().ReleaseFence(Fence); - - VERIFYVULKANRESULT(vkResetCommandBuffer(StagingCommandBuffer, 0x0)); - - vkFreeCommandBuffers(LogicalDevice, Device->GetImmediateContext().GetCommandBufferManager()->GetHandle(), 1, &StagingCommandBuffer); - Device->GetStagingManager().ReleaseBuffer(StagingBuffer); -#endif } void* FVulkanDynamicRHI::RHILockTexture2DArray(FTexture2DArrayRHIParamRef TextureRHI,uint32 TextureIndex,uint32 MipIndex,EResourceLockMode LockMode,uint32& DestStride,bool bLockWithinMiptail) @@ -930,21 +843,65 @@ void FVulkanDynamicRHI::RHIUnlockTexture2DArray(FTexture2DArrayRHIParamRef Textu void FVulkanDynamicRHI::RHIUpdateTexture2D(FTexture2DRHIParamRef TextureRHI, uint32 MipIndex, const struct FUpdateTextureRegion2D& UpdateRegion, uint32 SourcePitch, const uint8* SourceData) { - VULKAN_SIGNAL_UNIMPLEMENTED(); -#if 0 FVulkanTexture2D* Texture = ResourceCast(TextureRHI); -#endif - -} - -void FVulkanDynamicRHI::RHIUpdateTexture3D(FTexture3DRHIParamRef TextureRHI,uint32 MipIndex,const FUpdateTextureRegion3D& UpdateRegion,uint32 SourceRowPitch,uint32 SourceDepthPitch,const uint8* SourceData) -{ VULKAN_SIGNAL_UNIMPLEMENTED(); -#if 0 - FVulkanTexture3D* Texture = ResourceCast(TextureRHI); -#endif } +void FVulkanDynamicRHI::RHIUpdateTexture3D(FTexture3DRHIParamRef TextureRHI, uint32 MipIndex, const FUpdateTextureRegion3D& UpdateRegion, uint32 SourceRowPitch, uint32 SourceDepthPitch, const uint8* SourceData) +{ + FVulkanTexture3D* Texture = ResourceCast(TextureRHI); + + EPixelFormat PixelFormat = Texture->GetFormat(); + check(GPixelFormats[PixelFormat].BlockSizeX == 1); + check(GPixelFormats[PixelFormat].BlockSizeY == 1); + + VkFormat Format = (VkFormat)GPixelFormats[PixelFormat].PlatformFormat; + + // TO DO - add appropriate offsets to source data when necessary + check(UpdateRegion.SrcX == 0); + check(UpdateRegion.SrcY == 0); + check(UpdateRegion.SrcZ == 0); + + auto& Context = Device->GetImmediateContext(); + const auto& Limits = Device->GetLimits(); + const uint32 AlignedSourcePitch = Align(SourceRowPitch, Limits.optimalBufferCopyRowPitchAlignment); + const uint32 BufferSize = Align(UpdateRegion.Height * UpdateRegion.Depth * AlignedSourcePitch, Limits.minMemoryMapAlignment); + + auto* StagingBuffer = Device->GetStagingManager().AcquireBuffer(BufferSize); + void* Memory = StagingBuffer->GetMappedPointer(); + + uint32 Size = UpdateRegion.Height * UpdateRegion.Depth * SourceRowPitch; + check(Size <= BufferSize); + + //#todo-rco: Probably needs some work (see D3D12) + //FMemory::Memcpy(Memory, SourceData, Size); + FMemory::Memzero(Memory, Size); + + VkBufferImageCopy Region; + FMemory::Memzero(Region); + //#todo-rco: Might need an offset here? + check(UpdateRegion.SrcX == 0); + check(UpdateRegion.SrcY == 0); + check(UpdateRegion.SrcZ == 0); + //Region.bufferOffset = 0; + //Region.bufferRowLength = 0; + //Region.bufferImageHeight = 0; + Region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + Region.imageSubresource.mipLevel = MipIndex; + Region.imageSubresource.baseArrayLayer = 0; + Region.imageSubresource.layerCount = 1; + Region.imageOffset.x = UpdateRegion.SrcX; + Region.imageOffset.y = UpdateRegion.SrcY; + Region.imageOffset.z = UpdateRegion.SrcZ; + Region.imageExtent.width = UpdateRegion.Width; + Region.imageExtent.height = UpdateRegion.Height; + Region.imageExtent.depth = UpdateRegion.Depth; + vkCmdCopyBufferToImage(Device->GetImmediateContext().GetCommandBufferManager()->GetUploadCmdBuffer()->GetHandle(), StagingBuffer->GetHandle(), Texture->Surface.Image, VK_IMAGE_LAYOUT_GENERAL, 1, &Region); + + Device->GetStagingManager().ReleaseBuffer(nullptr, StagingBuffer); +} + + void FVulkanTextureView::Create(FVulkanDevice& Device, FVulkanSurface& Surface, VkImageViewType ViewType, VkFormat Format, uint32 NumMips) { VkImageViewCreateInfo ViewInfo; @@ -1030,15 +987,31 @@ FVulkanTextureBase::FVulkanTextureBase(FVulkanDevice& Device, VkImageViewType Re #endif // For now only 3D textures can have bulk-data parsed on creation time. - if(!CreateInfo.BulkData || Surface.GetTiling() != VK_IMAGE_TILING_OPTIMAL) + if (!CreateInfo.BulkData) { return; } + if (Surface.GetTiling() != VK_IMAGE_TILING_OPTIMAL) + { + return; + } + + check(Surface.GetViewType() == VK_IMAGE_VIEW_TYPE_3D); + // Transfer bulk data + VulkanRHI::FStagingBuffer* StagingBuffer = Device.GetStagingManager().AcquireBuffer(CreateInfo.BulkData->GetResourceBulkDataSize()); + void* Data = StagingBuffer->GetMappedPointer(); + + // Do copy + FMemory::Memcpy(Data, CreateInfo.BulkData->GetResourceBulkData(), CreateInfo.BulkData->GetResourceBulkDataSize()); + + FVulkanCmdBuffer* CmdBuffer = Device.GetImmediateContext().GetCommandBufferManager()->GetUploadCmdBuffer(); + ensure(CmdBuffer->IsOutsideRenderPass()); VkBufferImageCopy Region; FMemory::Memzero(Region); + //#todo-rco: Use real Buffer offset when switching to suballocations! Region.bufferOffset = 0; Region.bufferRowLength = Surface.Width; Region.bufferImageHeight = Surface.Height; @@ -1052,50 +1025,6 @@ FVulkanTextureBase::FVulkanTextureBase(FVulkanDevice& Device, VkImageViewType Re Region.imageExtent.height = Region.bufferImageHeight; Region.imageExtent.depth = Surface.Depth; - // Temporary buffer which will hold bulkdata - VkBufferCreateInfo BufferCreateInfo; - FMemory::Memzero(BufferCreateInfo); - BufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - BufferCreateInfo.flags = 0; - //BufferCreateInfo.pQueueFamilyIndices = NULL; - //BufferCreateInfo.queueFamilyIndexCount = 0; - //BufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - BufferCreateInfo.size = CreateInfo.BulkData->GetResourceBulkDataSize(); - BufferCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; - - VkBuffer Buffer; - VERIFYVULKANRESULT(vkCreateBuffer(Device.GetInstanceHandle(), &BufferCreateInfo, NULL, &Buffer)); - - VkMemoryRequirements MemReqs; - vkGetBufferMemoryRequirements(Device.GetInstanceHandle(), Buffer, &MemReqs); - - // Allocate device gmem - VkDeviceMemory Mem; - - //#todo-rco: USe StagingBuffers - VulkanRHI::FDeviceMemoryAllocation* Allocation = Device.GetMemoryManager().Alloc(MemReqs.size, MemReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, __FILE__, __LINE__); - Mem = Allocation->GetHandle(); - - //FPlatformMisc::LowLevelOutputDebugStringf(TEXT("** vkBindBufferMemory Buf %p MemHandle %p MemOffset %d Size %u\n"), (void*)Buffer, (void*)Mem, (uint32)0, (uint32)MemReqs.size); - VERIFYVULKANRESULT(vkBindBufferMemory(Device.GetInstanceHandle(), Buffer, Mem, 0)); - - void* Data = nullptr; - VERIFYVULKANRESULT(vkMapMemory(Device.GetInstanceHandle(), Mem, 0, MemReqs.size, 0, &Data)); - - // Do copy - FMemory::Memcpy(Data, CreateInfo.BulkData->GetResourceBulkData(), CreateInfo.BulkData->GetResourceBulkDataSize()); - - vkUnmapMemory(Device.GetInstanceHandle(), Mem); - -#if VULKAN_USE_NEW_COMMAND_BUFFERS - FVulkanCmdBuffer* CmdBuffer = Device.GetImmediateContext().GetCommandBufferManager()->GetActiveCmdBuffer(); - ensure(CmdBuffer->IsOutsideRenderPass()); -#else - //#todo-rco: FIX ME? - FVulkanCmdBuffer* CmdBuffer = Device.GetImmediateContext().GetCommandBufferManager()->Create(); - CmdBuffer->Begin(); -#endif - VkImageSubresourceRange SubresourceRange; FMemory::Memzero(SubresourceRange); SubresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; @@ -1103,24 +1032,14 @@ FVulkanTextureBase::FVulkanTextureBase(FVulkanDevice& Device, VkImageViewType Re SubresourceRange.levelCount = Surface.GetNumMips(); //SubresourceRange.baseArrayLayer = 0; SubresourceRange.layerCount = ArraySize; - VulkanSetImageLayout(CmdBuffer->GetHandle(), Surface.Image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, SubresourceRange); + VulkanSetImageLayout(CmdBuffer->GetHandle(), Surface.Image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, SubresourceRange); // Copy buffer to image - vkCmdCopyBufferToImage(CmdBuffer->GetHandle(), Buffer, Surface.Image, VK_IMAGE_LAYOUT_GENERAL, 1, &Region); + vkCmdCopyBufferToImage(CmdBuffer->GetHandle(), StagingBuffer->GetHandle(), Surface.Image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &Region); - VulkanSetImageLayout(CmdBuffer->GetHandle(), Surface.Image, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, SubresourceRange); + VulkanSetImageLayout(CmdBuffer->GetHandle(), Surface.Image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, SubresourceRange); -#if VULKAN_USE_NEW_COMMAND_BUFFERS -#else - Device.GetQueue()->SubmitBlocking(CmdBuffer); - //#todo-rco: FIX ME! - Device.GetImmediateContext().GetCommandBufferManager()->Destroy(CmdBuffer); - - vkDestroyBuffer(Device.GetInstanceHandle(), Buffer, nullptr); - -#endif - //#todo-rco: USe StagingBuffers - Device.GetMemoryManager().Free(Allocation); + Device.GetStagingManager().ReleaseBuffer(CmdBuffer, StagingBuffer); } FVulkanTextureBase::FVulkanTextureBase(FVulkanDevice& Device, VkImageViewType ResourceType, EPixelFormat Format, uint32 SizeX, uint32 SizeY, uint32 SizeZ, VkImage InImage, VkDeviceMemory InMem, uint32 UEFlags, const FRHIResourceCreateInfo& CreateInfo): @@ -1244,25 +1163,9 @@ void FVulkanDynamicRHI::RHIUnlockTextureCubeFace(FTextureCubeRHIParamRef Texture checkf(bFound, TEXT("Texture was not locked!")); } -#if VULKAN_USE_NEW_COMMAND_BUFFERS - FVulkanCmdBuffer* CmdBuffer = Device->GetImmediateContext().GetCommandBufferManager()->GetActiveCmdBuffer(); + FVulkanCmdBuffer* CmdBuffer = Device->GetImmediateContext().GetCommandBufferManager()->GetUploadCmdBuffer(); ensure(CmdBuffer->IsOutsideRenderPass()); VkCommandBuffer StagingCommandBuffer = CmdBuffer->GetHandle(); -#else - VkCommandBuffer StagingCommandBuffer; - VkCommandBufferAllocateInfo CmdBufferCreateInfo; - FMemory::Memzero(CmdBufferCreateInfo); - CmdBufferCreateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - CmdBufferCreateInfo.commandPool = Device->GetImmediateContext().GetCommandBufferManager()->GetHandle(); - CmdBufferCreateInfo.commandBufferCount = 1; - CmdBufferCreateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - VERIFYVULKANRESULT(vkAllocateCommandBuffers(LogicalDevice, &CmdBufferCreateInfo, &StagingCommandBuffer)); - - VkCommandBufferBeginInfo BufferBeginInfo; - FMemory::Memzero(BufferBeginInfo); - BufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - VERIFYVULKANRESULT(vkBeginCommandBuffer(StagingCommandBuffer, &BufferBeginInfo)); -#endif EPixelFormat Format = Texture->Surface.Format; uint32 MipWidth = FMath::Max(Texture->Surface.Width >> MipIndex, GPixelFormats[Format].BlockSizeX); uint32 MipHeight = FMath::Max(Texture->Surface.Height >> MipIndex, GPixelFormats[Format].BlockSizeY); @@ -1274,7 +1177,7 @@ void FVulkanDynamicRHI::RHIUnlockTextureCubeFace(FTextureCubeRHIParamRef Texture SubresourceRange.levelCount = 1; SubresourceRange.baseArrayLayer = FaceIndex; SubresourceRange.layerCount = 1; - VulkanSetImageLayout(StagingCommandBuffer, Texture->Surface.Image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, SubresourceRange); + VulkanSetImageLayout(StagingCommandBuffer, Texture->Surface.Image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, SubresourceRange); VkBufferImageCopy Region; FMemory::Memzero(Region); @@ -1289,28 +1192,11 @@ void FVulkanDynamicRHI::RHIUnlockTextureCubeFace(FTextureCubeRHIParamRef Texture Region.imageExtent.width = MipWidth; Region.imageExtent.height = MipHeight; Region.imageExtent.depth = 1; - vkCmdCopyBufferToImage(StagingCommandBuffer, StagingBuffer->GetHandle(), Texture->Surface.Image, VK_IMAGE_LAYOUT_GENERAL, 1, &Region); + vkCmdCopyBufferToImage(StagingCommandBuffer, StagingBuffer->GetHandle(), Texture->Surface.Image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &Region); - VulkanSetImageLayout(StagingCommandBuffer, Texture->Surface.Image, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, SubresourceRange); + VulkanSetImageLayout(StagingCommandBuffer, Texture->Surface.Image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, SubresourceRange); -#if VULKAN_USE_NEW_COMMAND_BUFFERS Device->GetStagingManager().ReleaseBuffer(CmdBuffer, StagingBuffer); -#else - VERIFYVULKANRESULT(vkEndCommandBuffer(StagingCommandBuffer)); - - auto* Fence = Device->GetFenceManager().AllocateFence(); - Device->GetQueue()->Submit2(StagingCommandBuffer, Fence); - - bool bSuccess = Device->GetFenceManager().WaitForFence(Fence, 0xFFFFFFFF); - check(bSuccess); - - Device->GetFenceManager().ReleaseFence(Fence); - - VERIFYVULKANRESULT(vkResetCommandBuffer(StagingCommandBuffer, 0x0)); - - vkFreeCommandBuffers(LogicalDevice, Device->GetImmediateContext().GetCommandBufferManager()->GetHandle(), 1, &StagingCommandBuffer); - Device->GetStagingManager().ReleaseBuffer(StagingBuffer); -#endif } void FVulkanDynamicRHI::RHIBindDebugLabelName(FTextureRHIParamRef TextureRHI, const TCHAR* Name) diff --git a/Engine/Source/Runtime/VulkanRHI/Private/VulkanUAV.cpp b/Engine/Source/Runtime/VulkanRHI/Private/VulkanUAV.cpp index ed038e1a44e5..be89b2303240 100644 --- a/Engine/Source/Runtime/VulkanRHI/Private/VulkanUAV.cpp +++ b/Engine/Source/Runtime/VulkanRHI/Private/VulkanUAV.cpp @@ -20,8 +20,8 @@ void FVulkanShaderResourceView::UpdateView(FVulkanDevice* Device) { SCOPE_CYCLE_COUNTER(STAT_VulkanSRVUpdateTime); // thanks to ref counting, overwriting the buffer will toss the old view - BufferView = new FVulkanBufferView(); - BufferView->Create(*Device, SourceVertexBuffer.GetReference(), BufferViewFormat, SourceVertexBuffer->GetOffset(), SourceVertexBuffer->GetSize()); + BufferView = new FVulkanBufferView(Device); + BufferView->Create(SourceVertexBuffer.GetReference(), BufferViewFormat, SourceVertexBuffer->GetOffset(), SourceVertexBuffer->GetSize()); } } } diff --git a/Engine/Source/Runtime/VulkanRHI/Private/VulkanUtil.cpp b/Engine/Source/Runtime/VulkanRHI/Private/VulkanUtil.cpp index 3260779a84b3..400cd3bc42b5 100644 --- a/Engine/Source/Runtime/VulkanRHI/Private/VulkanUtil.cpp +++ b/Engine/Source/Runtime/VulkanRHI/Private/VulkanUtil.cpp @@ -68,7 +68,7 @@ void FVulkanGPUTiming::StartTiming() if (StartTimestamp >= 0 && EndTimestamp >= 0) { auto& State = GTimestampQueryPool->Device->GetPendingState(); -#if VULKAN_USE_NEW_COMMAND_BUFFERS +#if 1//VULKAN_USE_NEW_COMMAND_BUFFERS check(0); #else GTimestampQueryPool->WriteTimestamp(State.GetCommandBuffer(), StartTimestamp, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT); @@ -90,7 +90,7 @@ void FVulkanGPUTiming::EndTiming() if (StartTimestamp >= 0 && EndTimestamp >= 0) { auto& State = GTimestampQueryPool->Device->GetPendingState(); -#if VULKAN_USE_NEW_COMMAND_BUFFERS +#if 1//VULKAN_USE_NEW_COMMAND_BUFFERS check(0); #else GTimestampQueryPool->WriteTimestamp(State.GetCommandBuffer(), EndTimestamp, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT); diff --git a/Engine/Source/Runtime/VulkanRHI/Private/VulkanViewport.cpp b/Engine/Source/Runtime/VulkanRHI/Private/VulkanViewport.cpp index 010aff7cc220..cd0c702f95a7 100644 --- a/Engine/Source/Runtime/VulkanRHI/Private/VulkanViewport.cpp +++ b/Engine/Source/Runtime/VulkanRHI/Private/VulkanViewport.cpp @@ -11,14 +11,15 @@ #include "VulkanContext.h" -FVulkanViewport::FVulkanViewport(FVulkanDynamicRHI* InRHI, void* WindowHandle, uint32 InSizeX, uint32 InSizeY, bool bInIsFullscreen, EPixelFormat InPreferredPixelFormat) : - RHI(InRHI), - SizeX(InSizeX), - SizeY(InSizeY), - bIsFullscreen(bInIsFullscreen), - PixelFormat(InPreferredPixelFormat), - CurrentBackBuffer(-1), - SwapChain(nullptr) +FVulkanViewport::FVulkanViewport(FVulkanDynamicRHI* InRHI, void* WindowHandle, uint32 InSizeX, uint32 InSizeY, bool bInIsFullscreen, EPixelFormat InPreferredPixelFormat) + : RHI(InRHI) + , SizeX(InSizeX) + , SizeY(InSizeY) + , bIsFullscreen(bInIsFullscreen) + , PixelFormat(InPreferredPixelFormat) + , CurrentBackBuffer(-1) + , SwapChain(nullptr) + , PendingImageSemaphore(nullptr) { check(IsInGameThread()); RHI->Viewports.Add(this); @@ -37,13 +38,8 @@ FVulkanViewport::FVulkanViewport(FVulkanDynamicRHI* InRHI, void* WindowHandle, u check(Images.Num() == NUM_BUFFERS); -#if VULKAN_USE_NEW_COMMAND_BUFFERS FVulkanCmdBuffer* CmdBuffer = RHI->Device->GetImmediateContext().GetCommandBufferManager()->GetActiveCmdBuffer(); check(CmdBuffer->IsOutsideRenderPass()); -#else - FVulkanCmdBuffer* CmdBuffer = RHI->Device->GetImmediateContext().GetCommandBufferManager()->Create(); - CmdBuffer->Begin(); -#endif for (int32 Index = 0, Count = Images.Num(); Index < Count; ++Index) { VkImage Image = Images[Index]; @@ -53,20 +49,7 @@ FVulkanViewport::FVulkanViewport(FVulkanDynamicRHI* InRHI, void* WindowHandle, u FName Name = FName(*FString::Printf(TEXT("BackBuffer%d"), Index)); BackBuffers[Index]->SetName(Name); - -#if VULKAN_USE_NEW_COMMAND_BUFFERS -#else -#if !PLATFORM_ANDROID - // Set to present src as the next calls will transition to color optimal - checkf(BackBuffers[Index]->Surface.ImageLayout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, TEXT("BackBuffers[%d]->Surface.ImageLayout is %d"), Index, BackBuffers[Index]->Surface.ImageLayout); -#endif -#endif } - -#if VULKAN_USE_NEW_COMMAND_BUFFERS -#else - RHI->Device->EndCommandBufferBlock(CmdBuffer); -#endif } FVulkanViewport::~FVulkanViewport() @@ -83,9 +66,10 @@ FVulkanViewport::~FVulkanViewport() RHI->Viewports.Remove(this); } + FVulkanFramebuffer::FVulkanFramebuffer(FVulkanDevice& Device, const FRHISetRenderTargetsInfo& InRTInfo, const FVulkanRenderTargetLayout& RTLayout, const FVulkanRenderPass& RenderPass) -: Framebuffer(VK_NULL_HANDLE) -, NumColorAttachments(0u) + : Framebuffer(VK_NULL_HANDLE) + , NumColorAttachments(0) { Attachments.Empty(RTLayout.GetNumAttachments()); @@ -101,7 +85,7 @@ FVulkanFramebuffer::FVulkanFramebuffer(FVulkanDevice& Device, const FRHISetRende #if VULKAN_USE_MSAA_RESOLVE_ATTACHMENTS if (Texture->MSAASurface) { -#if VULKAN_USE_NEW_COMMAND_BUFFERS +#if 1//VULKAN_USE_NEW_COMMAND_BUFFERS check(0); #endif Attachments.Add(Texture->MSAAView.View); @@ -112,7 +96,7 @@ FVulkanFramebuffer::FVulkanFramebuffer(FVulkanDevice& Device, const FRHISetRende Barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; //Barrier.pNext = NULL; Barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - Barrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT; + Barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT; Barrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL; Barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL; Barrier.image = Texture->Surface.Image; @@ -127,8 +111,6 @@ FVulkanFramebuffer::FVulkanFramebuffer(FVulkanDevice& Device, const FRHISetRende #endif Attachments.Add(Texture->View.View); -#if VULKAN_USE_NEW_COMMAND_BUFFERS -#else // Create a write-barrier WriteBarriers.AddZeroed(); VkImageMemoryBarrier& Barrier = WriteBarriers.Last(); @@ -136,17 +118,15 @@ FVulkanFramebuffer::FVulkanFramebuffer(FVulkanDevice& Device, const FRHISetRende //Barrier.pNext = NULL; Barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; Barrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT; - Barrier.oldLayout = Texture->Surface.ImageLayout; - Barrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + Barrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL; + Barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL; Barrier.image = Texture->Surface.Image; Barrier.subresourceRange.aspectMask = Texture->Surface.GetAspectMask(); //Barrier.subresourceRange.baseMipLevel = 0; Barrier.subresourceRange.levelCount = 1; //Barrier.subresourceRange.baseArrayLayer = 0; Barrier.subresourceRange.layerCount = 1; - Barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - Barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; -#endif + NumColorAttachments++; } @@ -165,10 +145,8 @@ FVulkanFramebuffer::FVulkanFramebuffer(FVulkanDevice& Device, const FRHISetRende Texture->Surface.GetNumMips()); } - Attachments.Add(Texture->View.View); + bool bHasStencil = (Texture->Surface.Format == PF_DepthStencil); -#if VULKAN_USE_NEW_COMMAND_BUFFERS -#else // Create a write-barrier WriteBarriers.AddZeroed(); VkImageMemoryBarrier& Barrier = WriteBarriers.Last(); @@ -177,17 +155,16 @@ FVulkanFramebuffer::FVulkanFramebuffer(FVulkanDevice& Device, const FRHISetRende Barrier.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; Barrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT; Barrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL; - Barrier.newLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + Barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL; Barrier.image = Texture->Surface.Image; - Barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - Barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; Barrier.subresourceRange.aspectMask = Texture->Surface.GetAspectMask(); //Barrier.subresourceRange.baseMipLevel = 0; Barrier.subresourceRange.levelCount = 1; //Barrier.subresourceRange.baseArrayLayer = 0; Barrier.subresourceRange.layerCount = 1; -#endif + + Attachments.Add(Texture->View.View); } VkFramebufferCreateInfo Info; @@ -253,21 +230,20 @@ bool FVulkanFramebuffer::Matches(const FRHISetRenderTargetsInfo& InRTInfo) const return true; } -#if VULKAN_USE_NEW_COMMAND_BUFFERS void FVulkanViewport::AcquireBackBuffer(FVulkanCmdBuffer* CmdBuffer) { - CurrentBackBuffer = SwapChain->AcquireImageIndex(); + CurrentBackBuffer = SwapChain->AcquireImageIndex(&PendingImageSemaphore); check(CurrentBackBuffer != -1); - VulkanSetImageLayoutSimple(CmdBuffer->GetHandle(), BackBuffers[CurrentBackBuffer]->Surface.Image, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + VulkanSetImageLayoutSimple(CmdBuffer->GetHandle(), BackBuffers[CurrentBackBuffer]->Surface.Image, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_IMAGE_LAYOUT_GENERAL); } void FVulkanViewport::PrepareBackBufferForPresent(FVulkanCmdBuffer* CmdBuffer) { check(CurrentBackBuffer != -1); - VulkanSetImageLayoutSimple(CmdBuffer->GetHandle(), BackBuffers[CurrentBackBuffer]->Surface.Image, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); + VulkanSetImageLayoutSimple(CmdBuffer->GetHandle(), BackBuffers[CurrentBackBuffer]->Surface.Image, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); } -void FVulkanFramebuffer::InsertWriteBarrier(FVulkanCmdBuffer* CmdBuffer) +void FVulkanFramebuffer::InsertWriteBarriers(FVulkanCmdBuffer* CmdBuffer) { if (WriteBarriers.Num() == 0) { @@ -280,21 +256,6 @@ void FVulkanFramebuffer::InsertWriteBarrier(FVulkanCmdBuffer* CmdBuffer) check(CmdBuffer->IsOutsideRenderPass()); vkCmdPipelineBarrier(CmdBuffer->GetHandle(), SrcStages, DestStages, 0, 0, nullptr, 0, nullptr, WriteBarriers.Num(), WriteBarriers.GetData()); } -#else -void FVulkanFramebuffer::InsertWriteBarrier(VkCommandBuffer cmd) -{ - if (WriteBarriers.Num() == 0) - { - return; - } - - const VkPipelineStageFlags SrcStages = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - const VkPipelineStageFlags DestStages = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; - - vkCmdPipelineBarrier(cmd, SrcStages, DestStages, - 0, 0, nullptr, 0, nullptr, WriteBarriers.Num(), WriteBarriers.GetData()); -} -#endif /*============================================================================= * The following RHI functions must be called from the main thread. @@ -324,13 +285,8 @@ void FVulkanDynamicRHI::WriteEndFrameTimestamp(void* Data) auto* TimestampQueryPool = This->Device->GetTimestampQueryPool(This->PresentCount % (uint32)FVulkanDevice::NumTimestampPools); if (TimestampQueryPool) { -#if VULKAN_USE_NEW_COMMAND_BUFFERS auto* CmdBuffer = This->Device->GetImmediateContext().GetCommandBufferManager()->GetActiveCmdBuffer(); TimestampQueryPool->WriteEndFrame(CmdBuffer->GetHandle()); -#else - auto& PendingState = This->Device->GetPendingState(); - TimestampQueryPool->WriteEndFrame(PendingState.GetCommandBuffer()); -#endif } } @@ -345,7 +301,6 @@ void FVulkanDynamicRHI::Present() check(Device); -#if VULKAN_USE_NEW_COMMAND_BUFFERS auto* CmdBufferManager = Device->GetImmediateContext().GetCommandBufferManager(); auto* CmdBuffer = CmdBufferManager->GetActiveCmdBuffer(); if (PendingState.IsRenderPassActive()) @@ -356,15 +311,8 @@ void FVulkanDynamicRHI::Present() WriteEndFrameTimestamp(this); CmdBuffer->End(); Device->GetQueue()->Submit(CmdBuffer); -#else - PendingState.SubmitPendingCommandBuffers(&WriteEndFrameTimestamp, this); -#endif -#if VULKAN_USE_NEW_COMMAND_BUFFERS DrawingViewport->GetSwapChain()->Present(Device->GetQueue()); -#else - Device->GetQueue()->Present(DrawingViewport->SwapChain, DrawingViewport->CurrentBackBuffer); -#endif bool bNativelyPresented = true; if (bNativelyPresented) @@ -397,9 +345,7 @@ void FVulkanDynamicRHI::Present() //#todo-rco: This needs to go on RHIEndFrame but the CmdBuffer index is not the correct one to read the stats out! VulkanRHI::GManager.GPUProfilingData.EndFrame(); -#if VULKAN_USE_NEW_COMMAND_BUFFERS Device->GetImmediateContext().GetCommandBufferManager()->PrepareForNewActiveCommandBuffer(); -#endif //#todo-rco: Consolidate 'end of frame' Device->GetImmediateContext().GetTempFrameAllocationBuffer().Reset(); @@ -420,11 +366,7 @@ void FVulkanDynamicRHI::Present() TimestampQueryPool->CalculateFrameTime(); } -#if VULKAN_USE_NEW_COMMAND_BUFFERS Device->GetTimestampQueryPool(QueryNextFrameIndex)->WriteStartFrame(CmdBufferManager->GetActiveCmdBuffer()->GetHandle()); -#else - Device->GetTimestampQueryPool(QueryNextFrameIndex)->WriteStartFrame(PendingState.GetCommandBuffer()); -#endif } PresentCount++; @@ -435,22 +377,14 @@ FTexture2DRHIRef FVulkanDynamicRHI::RHIGetViewportBackBuffer(FViewportRHIParamRe FVulkanViewport* Viewport = ResourceCast(ViewportRHI); if (Viewport->CurrentBackBuffer < 0) { -#if VULKAN_USE_NEW_COMMAND_BUFFERS Viewport->AcquireBackBuffer(Device->GetImmediateContext().GetCommandBufferManager()->GetActiveCmdBuffer()); -#else - // SMEDIS: Acquire a new backbuffer now, in case RHIBeginDrawingViewport() hasn't been called yet. - Viewport->CurrentBackBuffer = Device->GetQueue()->AquireImageIndex(Viewport->SwapChain); -#endif } return Viewport->GetBackBuffer(); } void FVulkanDynamicRHI::RHIAdvanceFrameForGetViewportBackBuffer() { -#if VULKAN_USE_NEW_COMMAND_BUFFERS //#todo-rco: Do a pass to clear unused or expired elements in managers -#else -#endif } void FVulkanCommandListContext::RHISetViewport(uint32 MinX, uint32 MinY, float MinZ, uint32 MaxX, uint32 MaxY, float MaxZ) diff --git a/Engine/Source/Runtime/VulkanRHI/Public/VulkanConfiguration.h b/Engine/Source/Runtime/VulkanRHI/Public/VulkanConfiguration.h index 587ce1469d93..1b3ea4d4686f 100644 --- a/Engine/Source/Runtime/VulkanRHI/Public/VulkanConfiguration.h +++ b/Engine/Source/Runtime/VulkanRHI/Public/VulkanConfiguration.h @@ -25,7 +25,7 @@ // constants we probably will change a few times #define VULKAN_UB_RING_BUFFER_SIZE (8 * 1024 * 1024) -#define VULKAN_TEMP_FRAME_ALLOCATOR_SIZE (1 * 1024 * 1024) +#define VULKAN_TEMP_FRAME_ALLOCATOR_SIZE (8 * 1024 * 1024) //@NOTE: VULKAN_NUM_IMAGE_BUFFERS should be smaller than VULKAN_NUM_COMMAND_BUFFERS, to make sure that we wait for the fence before we reset the cmd buffer //@TODO: Clean up VULKAN_NUM_IMAGE_BUFFERS and VULKAN_NUM_COMMAND_BUFFERS once the Vulkan API and SDK stabilizes. @@ -94,10 +94,7 @@ inline EDescriptorSetStage GetDescriptorSetForStage(EShaderFrequency Stage) #define VULKAN_ENABLE_AGGRESSIVE_STATS 1 -#define VULKAN_ENABLE_PIPELINE_CACHE 1 - -//#todo-rco: Test on Android -#define VULKAN_USE_NEW_COMMAND_BUFFERS 0//PLATFORM_WINDOWS +#define VULKAN_ENABLE_PIPELINE_CACHE 0 #define VULKAN_ENABLE_RHI_DEBUGGING 1 diff --git a/Engine/Source/Runtime/VulkanRHI/Public/VulkanMemory.h b/Engine/Source/Runtime/VulkanRHI/Public/VulkanMemory.h index 2712a178857e..522175839558 100644 --- a/Engine/Source/Runtime/VulkanRHI/Public/VulkanMemory.h +++ b/Engine/Source/Runtime/VulkanRHI/Public/VulkanMemory.h @@ -108,11 +108,6 @@ namespace VulkanRHI void* Map(VkDeviceSize Size, VkDeviceSize Offset); void Unmap(); - inline void* GetMappedPointer() - { - return MappedPointer; - } - inline bool CanBeMapped() const { return bCanBeMapped != 0; @@ -123,6 +118,12 @@ namespace VulkanRHI return !!MappedPointer; } + inline void* GetMappedPointer() + { + check(IsMapped()); + return MappedPointer; + } + inline bool IsCoherent() const { return bIsCoherent != 0; @@ -409,6 +410,11 @@ namespace VulkanRHI return AlignedOffset; } + inline uint32 GetSize() const + { + return RequestedSize; + } + protected: uint32 RequestedSize; uint32 AlignedOffset; @@ -435,6 +441,13 @@ namespace VulkanRHI return Handle; } + FBufferAllocation* GetBufferAllocation() + { + return Owner; + } + + void* GetMappedPointer(); + protected: friend class FBufferAllocation; FBufferAllocation* Owner; @@ -475,6 +488,16 @@ namespace VulkanRHI return TryAllocateNoLocking(Size, File, Line); } + uint32 GetAlignment() const + { + return Alignment; + } + + void* GetMappedPointer() + { + return MemoryAllocation->GetMappedPointer(); + } + protected: FResourceHeapManager* Owner; uint32 MemoryTypeIndex; @@ -670,6 +693,10 @@ namespace VulkanRHI uint32 TypeIndex = 0; VERIFYVULKANRESULT(DeviceMemoryManager->GetMemoryTypeFromProperties(MemoryReqs.memoryTypeBits, MemoryPropertyFlags, &TypeIndex)); bool bMapped = (MemoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; + if (!ResourceHeaps[TypeIndex]) + { + UE_LOG(LogVulkanRHI, Fatal, TEXT("Missing memory type index %d, MemSize %d, MemPropTypeBits %u, MemPropertyFlags %u, %s(%d)"), TypeIndex, (uint32)MemoryReqs.size, (uint32)MemoryReqs.memoryTypeBits, (uint32)MemoryPropertyFlags, ANSI_TO_TCHAR(File), Line); + } return ResourceHeaps[TypeIndex]->AllocateResource(MemoryReqs.size, MemoryReqs.alignment, false, bMapped, File, Line); } @@ -765,16 +792,15 @@ namespace VulkanRHI FStagingBuffer* AcquireBuffer(uint32 Size, VkBufferUsageFlags InUsageFlags = VK_BUFFER_USAGE_TRANSFER_SRC_BIT); -#if VULKAN_USE_NEW_COMMAND_BUFFERS // Sets pointer to nullptr void ReleaseBuffer(FVulkanCmdBuffer* CmdBuffer, FStagingBuffer*& StagingBuffer); -#else - // Sets pointer to nullptr - void ReleaseBuffer(FStagingBuffer*& StagingBuffer); -#endif void ProcessPendingFree(bool bImmediately = false); +#if UE_BUILD_DEBUG || UE_BUILD_DEVELOPMENT + void DumpMemory(); +#endif + protected: struct FPendingItem { @@ -784,9 +810,7 @@ namespace VulkanRHI }; TArray UsedStagingBuffers; -#if VULKAN_USE_NEW_COMMAND_BUFFERS TArray PendingFreeStagingBuffers; -#endif TArray FreeStagingBuffers; FVulkanDevice* Device; @@ -929,27 +953,40 @@ namespace VulkanRHI struct FTempAllocInfo { void* Data; - uint32 Offset; - VkBuffer Buffer; + + // Offset into the locked area + uint32 CurrentOffset; + + FBufferSuballocation* BufferSuballocation; + + inline uint32 GetBindOffset() const + { + return BufferSuballocation->GetOffset() + CurrentOffset; + } + + inline VkBuffer GetHandle() const + { + return BufferSuballocation->GetHandle(); + } }; bool Alloc(uint32 InSize, uint32 InAlignment, FTempAllocInfo& OutInfo); - inline VkBuffer GetHandle() const - { - return Buffer[BufferIndex]->GetHandle(); - } - void Reset(); protected: uint8* MappedData[NUM_RENDER_BUFFERS]; uint8* CurrentData[NUM_RENDER_BUFFERS]; - FStagingBuffer* Buffer[NUM_RENDER_BUFFERS]; + TRefCountPtr BufferSuballocations[NUM_RENDER_BUFFERS]; uint32 BufferIndex; uint32 Size; uint32 PeakUsed; friend class FVulkanCommandListContext; }; + + inline void* FBufferSuballocation::GetMappedPointer() + { + return Owner->GetMappedPointer(); + } } diff --git a/Engine/Source/Runtime/VulkanRHI/Public/VulkanRHI.h b/Engine/Source/Runtime/VulkanRHI/Public/VulkanRHI.h index 955e0cc26f4a..ddcf4f847b52 100644 --- a/Engine/Source/Runtime/VulkanRHI/Public/VulkanRHI.h +++ b/Engine/Source/Runtime/VulkanRHI/Public/VulkanRHI.h @@ -192,10 +192,12 @@ protected: #if UE_BUILD_DEBUG || UE_BUILD_DEVELOPMENT IConsoleObject* DumpMemoryCmd; +public: static void DumpMemory(); #endif #if VULKAN_HAS_DEBUGGING_ENABLED +protected: VkDebugReportCallbackEXT MsgCallback; void SetupDebugLayerCallback(); void RemoveDebugLayerCallback(); diff --git a/Engine/Source/Runtime/VulkanRHI/Public/VulkanResources.h b/Engine/Source/Runtime/VulkanRHI/Public/VulkanResources.h index b306b0de5e67..e49e3ea035b3 100644 --- a/Engine/Source/Runtime/VulkanRHI/Public/VulkanResources.h +++ b/Engine/Source/Runtime/VulkanRHI/Public/VulkanResources.h @@ -229,13 +229,8 @@ public: uint8 FormatKey; private: -#if VULKAN_USE_NEW_COMMAND_BUFFERS // Used to clear render-target objects on creation void Clear(const FClearValueBinding& ClearValueBinding, bool bTransitionToPresentable); -#else - // Used to clear render-target objects on creation - void ClearBlocking(const FClearValueBinding& ClearValueBinding, bool bTransitionToPresentable); -#endif private: // Linear or Optimal. Based on tiling, map/unmap is handled differently. @@ -553,17 +548,23 @@ public: }; -struct FVulkanBufferView : public FRHIResource +struct FVulkanBufferView : public FRHIResource, public VulkanRHI::FDeviceChild { - FVulkanBufferView() : - View(VK_NULL_HANDLE), - Flags(0) + FVulkanBufferView(FVulkanDevice* InDevice) + : VulkanRHI::FDeviceChild(InDevice) + , View(VK_NULL_HANDLE) + , Flags(0) { } - void Create(FVulkanDevice& Device, FVulkanBuffer& Buffer, EPixelFormat Format, uint32 Offset, uint32 Size); - void Create(FVulkanDevice& Device, FVulkanResourceMultiBuffer* Buffer, EPixelFormat Format, uint32 Offset, uint32 Size); - void Destroy(FVulkanDevice& Device); + virtual ~FVulkanBufferView() + { + Destroy(); + } + + void Create(FVulkanBuffer& Buffer, EPixelFormat Format, uint32 Offset, uint32 Size); + void Create(FVulkanResourceMultiBuffer* Buffer, EPixelFormat Format, uint32 Offset, uint32 Size); + void Destroy(); VkBufferView View; VkFlags Flags; @@ -611,12 +612,26 @@ public: // allocate some space in the ring buffer uint64 AllocateMemory(uint64 Size, uint32 Alignment); - VulkanRHI::FStagingBuffer* Buffer; + inline uint32 GetBufferOffset() const + { + return BufferSuballocation->GetOffset(); + } + + inline VkBuffer GetHandle() const + { + return BufferSuballocation->GetHandle(); + } + + inline void* GetMappedPointer() + { + return BufferSuballocation->GetMappedPointer(); + } protected: uint64 BufferSize; uint64 BufferOffset; uint32 MinAlignment; + VulkanRHI::FBufferSuballocation* BufferSuballocation; }; class FVulkanResourceMultiBuffer : public VulkanRHI::FDeviceChild @@ -629,7 +644,7 @@ public: { if (NumBuffers == 0) { - return VolatileLockInfo.Buffer; + return VolatileLockInfo.GetHandle(); } return Buffers[DynamicBufferIndex]->GetHandle(); } @@ -639,11 +654,12 @@ public: return NumBuffers > 1; } + // Offset used for Binding a VkBuffer inline uint32 GetOffset() const { if (NumBuffers == 0) { - return VolatileLockInfo.Offset; + return VolatileLockInfo.GetBindOffset(); } return Buffers[DynamicBufferIndex]->GetOffset(); } @@ -815,7 +831,7 @@ public: class FVulkanPipeline* PrepareForDraw(const struct FVulkanPipelineGraphicsKey& PipelineKey, uint32 VertexInputKey, const struct FVulkanPipelineState& State); - void UpdateDescriptorSets(FVulkanGlobalUniformPool* GlobalUniformPool); + void UpdateDescriptorSets(FVulkanCommandListContext* CmdListContext, FVulkanCmdBuffer* CmdBuffer, FVulkanGlobalUniformPool* GlobalUniformPool); void BindDescriptorSets(FVulkanCmdBuffer* Cmd); @@ -1052,10 +1068,33 @@ private: // these are the cache pipeline state objects used in this BSS TMap PipelineCache; - // descriptor set objects used by this BSS - uint64 LastFrameRendered; - int32 CurrentDS[VULKAN_NUM_COMMAND_BUFFERS]; - TArray DescriptorSets[VULKAN_NUM_COMMAND_BUFFERS]; + struct FDescriptorSetsPair + { + uint64 FenceCounter; + FVulkanDescriptorSets* DescriptorSets; + + FDescriptorSetsPair() + : FenceCounter(0) + , DescriptorSets(nullptr) + { + } + + ~FDescriptorSetsPair(); + }; + + struct FDescriptorSetsEntry + { + FVulkanCmdBuffer* CmdBuffer; + TArray Pairs; + + FDescriptorSetsEntry(FVulkanCmdBuffer* InCmdBuffer) + : CmdBuffer(InCmdBuffer) + { + } + }; + TArray DescriptorSetsEntries; + + FVulkanDescriptorSets* RequestDescriptorSets(FVulkanCmdBuffer* CmdBuffer); }; template diff --git a/Engine/Source/Runtime/VulkanRHI/Public/VulkanViewport.h b/Engine/Source/Runtime/VulkanRHI/Public/VulkanViewport.h index 2e9f2f394c74..1d34543617ab 100644 --- a/Engine/Source/Runtime/VulkanRHI/Public/VulkanViewport.h +++ b/Engine/Source/Runtime/VulkanRHI/Public/VulkanViewport.h @@ -11,6 +11,7 @@ class FVulkanDynamicRHI; class FVulkanSwapChain; class FVulkanQueue; +struct FVulkanSemaphore; class FVulkanViewport : public FRHIViewport { @@ -33,17 +34,20 @@ public: FIntPoint GetSizeXY() const { return FIntPoint(SizeX, SizeY); } -#if VULKAN_USE_NEW_COMMAND_BUFFERS FVulkanSwapChain* GetSwapChain() { return SwapChain; } + FVulkanSemaphore* AcquirePendingSemaphore() + { + FVulkanSemaphore* Semaphore = PendingImageSemaphore; + PendingImageSemaphore = nullptr; + return Semaphore; + } + void AcquireBackBuffer(FVulkanCmdBuffer* CmdBuffer); void PrepareBackBufferForPresent(FVulkanCmdBuffer* CmdBuffer); -#else -#endif - protected: TRefCountPtr BackBuffers[NUM_BUFFERS]; @@ -55,6 +59,8 @@ protected: int32 CurrentBackBuffer; FVulkanSwapChain* SwapChain; + FVulkanSemaphore* PendingImageSemaphore; + friend class FVulkanDynamicRHI; friend class FVulkanCommandListContext; }; diff --git a/Engine/Source/Runtime/Windows/D3D11RHI/Private/D3D11Texture.cpp b/Engine/Source/Runtime/Windows/D3D11RHI/Private/D3D11Texture.cpp index 1c2406eeff59..d387cf13ba11 100644 --- a/Engine/Source/Runtime/Windows/D3D11RHI/Private/D3D11Texture.cpp +++ b/Engine/Source/Runtime/Windows/D3D11RHI/Private/D3D11Texture.cpp @@ -481,7 +481,7 @@ TD3D11Texture2D* FD3D11DynamicRHI::CreateD3D11Texture2D(uint32 bool bPooledTexture = true; - if (GMaxRHIFeatureLevel <= ERHIFeatureLevel::ES2) + if (GMaxRHIFeatureLevel <= ERHIFeatureLevel::ES3_1) { // Remove sRGB read flag when not supported Flags &= ~TexCreate_SRGB; @@ -1007,7 +1007,7 @@ FTexture2DRHIRef FD3D11DynamicRHI::RHIAsyncCreateTexture2D(uint32 SizeX,uint32 S check(GRHISupportsAsyncTextureCreation); check((Flags & InvalidFlags) == 0); - if (GMaxRHIFeatureLevel <= ERHIFeatureLevel::ES2) + if (GMaxRHIFeatureLevel <= ERHIFeatureLevel::ES3_1) { // Remove sRGB read flag when not supported Flags &= ~TexCreate_SRGB; diff --git a/Engine/Source/Runtime/Windows/D3D12RHI/Private/D3D12Texture.cpp b/Engine/Source/Runtime/Windows/D3D12RHI/Private/D3D12Texture.cpp index 23f014419a77..804a5eac1b72 100644 --- a/Engine/Source/Runtime/Windows/D3D12RHI/Private/D3D12Texture.cpp +++ b/Engine/Source/Runtime/Windows/D3D12RHI/Private/D3D12Texture.cpp @@ -663,7 +663,7 @@ TD3D12Texture2D* FD3D12DynamicRHI::CreateD3D11Texture2D(uint32 bool bPooledTexture = true; - if (GMaxRHIFeatureLevel <= ERHIFeatureLevel::ES2) + if (GMaxRHIFeatureLevel <= ERHIFeatureLevel::ES3_1) { // Remove sRGB read flag when not supported Flags &= ~TexCreate_SRGB; @@ -1244,7 +1244,7 @@ FTexture2DRHIRef FD3D12DynamicRHI::RHIAsyncCreateTexture2D(uint32 SizeX, uint32 check(GRHISupportsAsyncTextureCreation); check((Flags & InvalidFlags) == 0); - if (GMaxRHIFeatureLevel <= ERHIFeatureLevel::ES2) + if (GMaxRHIFeatureLevel <= ERHIFeatureLevel::ES3_1) { // Remove sRGB read flag when not supported Flags &= ~TexCreate_SRGB; @@ -1992,7 +1992,7 @@ FTexture2DRHIRef FD3D12DynamicRHI::RHICreateTexture2DFromD3D12Resource(uint8 For SCOPE_CYCLE_COUNTER(STAT_D3D12CreateTextureTime); - if (GMaxRHIFeatureLevel <= ERHIFeatureLevel::ES2) + if (GMaxRHIFeatureLevel <= ERHIFeatureLevel::ES3_1) { // Remove sRGB read flag when not supported Flags &= ~TexCreate_SRGB; diff --git a/README.md b/README.md index 85a48e9f35c2..be705af28309 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,6 @@ We publish source for the engine in three rolling branches: The **[release branch](https://github.com/EpicGames/UnrealEngine/tree/release)** is extensively tested by our QA team and makes a great starting point for learning the engine or making your own games. We work hard to make releases stable and reliable, and aim to publish new releases every few months. ->**Important**: The Release branch has unintentionally been overwritten with code from the 4.11 Previews, and is *not* currently the latest and stable release. Please use Tags to grab the latest 4.10 release for our most stable version. This message will be removed when this matter has been resolved. The **[promoted branch](https://github.com/EpicGames/UnrealEngine/tree/promoted)** is updated with builds for our artists and designers to use. We try to update it daily (though we often catch things that prevent us from doing so) and it's a good balance between getting the latest cool stuff and knowing most things work.