From 93047290bbdc57b25ffbecd61a32afd9b4134792 Mon Sep 17 00:00:00 2001 From: Gil Gribb Date: Mon, 18 Jul 2016 17:17:08 -0400 Subject: [PATCH] Copying //UE4/Dev-Rendering to //UE4/Dev-Main (Source: //UE4/Dev-Rendering @ 3054480) #lockdown Nick.Penwarden #rb none ========================== MAJOR FEATURES + CHANGES ========================== Change 3045482 on 2016/07/11 by Zabir.Hoque DX12 Quries need to individually track their syncpoints. Only when resolving a query on the same frame should be stall. Change 3045929 on 2016/07/12 by Simon.Tovey Removing some deprecated node types from Niagara Change 3045951 on 2016/07/12 by Ben.Woodhouse D3D11 Log detailed live device info on shutdown if the debug layer is enabled (including resource types) Change 3046019 on 2016/07/12 by Chris.Bunner Fixed typo in material input name. #jira UE-5575 Change 3046053 on 2016/07/12 by Rolando.Caloca DR - Fix GL4 shutdown #jira UE-32799 Change 3046055 on 2016/07/12 by Rolando.Caloca DR - vk - Fix NumInstances=0 Change 3046063 on 2016/07/12 by Rolando.Caloca DR - vk - Added flat to uint layouts per glslang - Fix bad extension on dumped shaders Change 3046067 on 2016/07/12 by Rolando.Caloca DR - vk - Fix check when not using color RT - Added queue submit & present counters Change 3046088 on 2016/07/12 by Ben.Woodhouse Live GPU stats A non-hierarchical realtime high level GPU profiler with support for cumulative stat recording. Stats are added with SCOPED_GPU_STAT macros, e.g. SCOPED_GPU_STAT(RHICmdList, Stat_GPU_Distortion) The bulk of the files in this change are simply instrumentation for the renderer. The core changes are in SceneUtils.cpp/h and D3D11Query.cpp (this is the XB1/DX11X implementation of timestamp RHI queries, which was missing) Note: this is currently disabled by default. Enable with the cvar r.gpustatsenabled Tested on PC, XB1, PS4 Change 3046128 on 2016/07/12 by Olaf.Piesche Max draw distance and fade range for lights, requested by JonL Change 3046183 on 2016/07/12 by Ben.Woodhouse PR #2532: Fix SSAO being applied in unlit viewmode (Contributed by nick-penwarden) Change 3046223 on 2016/07/12 by Luke.Thatcher Fix Scene Cube Captures. SceneCaptureSource flag on the ViewFamily was not set for cube components. #jira UE-32345 Change 3046228 on 2016/07/12 by Marc.Olano Add Voronoi noise to Noise material node. Four versions with differing speed/quality levels accessed through the Quality value in the material node. Tooltips give estimates of the cost of each. Also includes spiffy new Rand3DPCG16 and Rand3DPCG32 int3 to int3 hash functions, and a 20% improvement on the computed gradient noise. Change 3046269 on 2016/07/12 by Rolando.Caloca DR - Skip flush on RHIDiscardRenderTargets and only use it on platforms that need it (ie OpenGL) Change 3046294 on 2016/07/12 by Rolando.Caloca DR - Fix static analyisis warning C6326: Potential comparison of a constant with another constant. Change 3046295 on 2016/07/12 by Rolando.Caloca DR - Fix the previous fix Change 3046731 on 2016/07/12 by Marc.Olano Fix typo in shader random number constant: repeated extra digit made it too big. Change 3046796 on 2016/07/12 by Uriel.Doyon The texture streaming manager now keeps a set of all valid textures. This is used to prevent from indirecting deleted memory upon SetTexturesRemovedTimestamp. #jira UE-33048 Change 3046800 on 2016/07/12 by Rolando.Caloca DR - vk - Added create image & renderpass dump Change 3046845 on 2016/07/12 by John.Billon Forgot to apply MaxGPUSkinBones Cvar access changes in a few locations. Change 3047023 on 2016/07/12 by Olaf.Piesche Niagara: -a bit of cleanup -now store and double buffer attributes individually, eliminating unnecessary copy of unused attributes -removed FNiagaraConstantMap, replaced with an instance of FNiagaraConstants -some code simplification -removed some deprecated structs and code used only by old content Change 3047052 on 2016/07/12 by Zabir.Hoque Unshelved from pending changelist '3044062': PR #2588: Adding blend mode BLEND_AlphaComposite (4.12) (Contributed by moritz-wundke) Change 3047727 on 2016/07/13 by Luke.Thatcher Fix Scene Capture Components only updating every other frame. #jira UE-32581 Change 3047919 on 2016/07/13 by Olaf.Piesche CMask decode, use in deferred decals, for PS4 Change 3047921 on 2016/07/13 by Uriel.Doyon "Build Texture Streaming" will now remove duplicate error msg when computing texcoord scales. Also, several texture messages are packed on the same line if they relate to the same material. Change 3047952 on 2016/07/13 by Rolando.Caloca DR - vk - Initial prep pass for separating combined images & samplers Change 3048648 on 2016/07/13 by Marcus.Wassmer Fix rare GPU hang when asynctexture reallocs would overlap with EndFrame Change 3049058 on 2016/07/13 by Rolando.Caloca DR - vk - timestamps Change 3049725 on 2016/07/14 by Marcus.Wassmer Fix autosdk bug where not having a platform directory sync'd at all would break manual SDK detection Change 3049742 on 2016/07/14 by Rolando.Caloca DR - Fix warning Change 3049902 on 2016/07/14 by Rolando.Caloca DR - Fix typo Change 3050345 on 2016/07/14 by Olaf.Piesche UE-23925 Clamping noise tessellation for beams at a high but sensible value; also making sure during beam index buffer building that we never get over 2^16 indices; this is a bit hokey, but there are so many variables that can influence triangle/index count, that this is the only way to be sure (short of nuking the entire site from orbit). Change 3050409 on 2016/07/14 by Olaf.Piesche Replicating 3049049; missing break and check for active particles when resolving a source point to avoid a potential crash Change 3050809 on 2016/07/14 by Rolando.Caloca DR - vk - Remove redundant validation layers Change 3051319 on 2016/07/15 by Ben.Woodhouse Fix for world space camera position not being exposed in decal pixel shaders; also fixes decal lighting missing spec and reflection The fix was to calculate ResolvedView at the top of the shader. Previously this was not initialized #jira UE-31976 Change 3051692 on 2016/07/15 by Rolando.Caloca DR - vk - Enable RHI thread by default Change 3052103 on 2016/07/15 by Uriel.Doyon Disabled depth offset in depth only pixel shaders when using debug view shaders (to prevent Z fighting). #jira UE-32765 Change 3052140 on 2016/07/15 by Rolando.Caloca DR - vk - Fix shader snafu Change 3052495 on 2016/07/15 by Rolando.Caloca DR - Fix for Win32 compile #jira UE-33349 Change 3052536 on 2016/07/15 by Uriel.Doyon Fixed texture streaming overbudget warning when using per texture bias. [CL 3054554 by Gil Gribb in Main branch] --- Engine/Config/BaseInput.ini | 1 + .../SpriteEditorViewportClient.cpp | 1 + .../TileMapEditorViewportClient.cpp | 1 + Engine/Shaders/BasePassPixelShader.usf | 32 +- Engine/Shaders/Common.usf | 28 +- Engine/Shaders/DeferredDecal.usf | 2 + Engine/Shaders/Definitions.usf | 4 + Engine/Shaders/DepthOnlyPixelShader.usf | 5 + Engine/Shaders/MobileBasePassPixelShader.usf | 4 + Engine/Shaders/RTWriteMaskDecode.usf | 26 + Engine/Shaders/Random.usf | 228 +- Engine/Shaders/SimpleElementPixelShader.usf | 4 + Engine/Shaders/VulkanCommon.usf | 2 +- .../Private/MaterialUtilities.cpp | 109 +- .../Public/MaterialUtilities.h | 57 +- .../MeshUtilities/Private/MeshUtilities.cpp | 4 +- .../Private/VulkanBackend.cpp | 185 +- .../Private/VulkanBackend.h | 15 +- .../Private/VulkanShaderCompiler.cpp | 70 +- .../Private/SMaterialEditorViewport.cpp | 2 +- .../NiagaraEditor/NiagaraEditor.Build.cs | 5 +- .../NiagaraEditor/Private/NiagaraCompiler.cpp | 12 +- ...aEmitterPropertiesDetailsCustomization.cpp | 12 +- .../Private/NiagaraNodeConstant.cpp | 4 - .../Private/NiagaraNodeGetAttr.cpp | 4 - .../Private/NiagaraNodeOutputUpdate.cpp | 6 - .../Private/NiagaraScriptSource.cpp | 2 +- .../Private/SNiagaraEffectEditorWidget.cpp | 5 +- .../Public/NiagaraNodeConstant.h | 6 - .../NiagaraEditor/Public/NiagaraNodeGetAttr.h | 4 - .../Public/NiagaraNodeOutputUpdate.h | 6 - .../UnrealEd/Private/EditorBuildUtils.cpp | 7 +- .../Private/Lightmass/LightmassRender.cpp | 9 +- .../UnrealEd/Private/MaterialGraphNode.cpp | 6 +- .../Configuration/UEBuildPlatform.cs | 6 +- .../Private/ImportExport/Material.cpp | 2 +- .../UnrealLightmass/Public/MaterialExport.h | 3 +- .../Apple/MetalRHI/Private/MetalRHI.cpp | 3 +- .../Source/Runtime/Core/Public/Stats/Stats2.h | 1 + .../Runtime/CoreUObject/Classes/Object.h | 1 + .../Classes/Components/LightComponent.h | 6 + .../Engine/Classes/Engine/EngineTypes.h | 1 + .../Classes/Materials/MaterialExpressionIf.h | 2 +- .../Materials/MaterialExpressionNoise.h | 15 +- .../Particles/Beam/ParticleModuleBeamNoise.h | 2 + .../Engine/Private/BatchedElements.cpp | 3 + .../Components/SceneCaptureComponent.cpp | 6 +- .../Engine/Private/DestructibleMesh.cpp | 7 +- .../Runtime/Engine/Private/LevelTick.cpp | 3 - .../Private/Materials/MaterialExpressions.cpp | 11 +- .../Private/Materials/MaterialShader.cpp | 1 + .../Private/Materials/MaterialShared.cpp | 5 + .../Private/Particles/ParticleBeamModules.cpp | 7 + .../Particles/ParticleGpuSimulation.cpp | 5 + .../Particles/ParticleSystemRender.cpp | 43 +- .../ParticleTrail2EmitterInstance.cpp | 3 +- .../Engine/Private/PointLightSceneProxy.h | 14 + .../Runtime/Engine/Private/SceneUtils.cpp | 380 +++ .../Private/ShaderCompiler/ShaderCompiler.cpp | 31 +- .../Engine/Private/SkeletalRenderCPUSkin.cpp | 7 +- .../Streaming/AsyncTextureStreaming.cpp | 81 +- .../Streaming/StreamingManagerTexture.cpp | 15 +- .../Streaming/StreamingManagerTexture.h | 3 + .../Private/Streaming/StreamingTexture.cpp | 52 +- .../Private/Streaming/StreamingTexture.h | 6 + .../Engine/Private/UserInterface/Canvas.cpp | 2 + .../Runtime/Engine/Public/PixelFormat.h | 6 +- .../Runtime/Engine/Public/SceneManagement.h | 3 + .../Source/Runtime/Engine/Public/SceneUtils.h | 89 + .../Launch/Private/LaunchEngineLoop.cpp | 3 + .../Niagara/Classes/NiagaraConstants.h | 10 +- .../Runtime/Niagara/Classes/NiagaraDataSet.h | 208 +- .../Runtime/Niagara/Classes/NiagaraEffect.h | 11 +- .../Classes/NiagaraEmitterProperties.h | 35 - .../Runtime/Niagara/Classes/NiagaraScript.h | 2 + .../Niagara/Classes/NiagaraSimulation.h | 17 +- .../Runtime/Niagara/NiagaraConstantSet.h | 135 +- .../Niagara/NiagaraScriptConstantData.h | 12 +- .../Runtime/Niagara/Private/NiagaraCommon.cpp | 16 + .../Niagara/Private/NiagaraConstantSet.cpp | 205 +- .../Runtime/Niagara/Private/NiagaraEffect.cpp | 13 +- .../Niagara/Private/NiagaraEffectRenderer.cpp | 21 +- .../Private/NiagaraEmitterProperties.cpp | 39 - .../Niagara/Private/NiagaraSimulation.cpp | 263 ++- .../Runtime/Niagara/Public/NiagaraCommon.h | 18 + .../Niagara/Public/NiagaraFunctionLibrary.h | 2 +- .../OpenGLDrv/Private/OpenGLCommands.cpp | 11 +- .../OpenGLDrv/Private/OpenGLDevice.cpp | 1 + .../OpenGLDrv/Private/OpenGLShaders.cpp | 7 +- .../Private/Windows/OpenGLWindows.cpp | 18 +- Engine/Source/Runtime/RHI/Private/RHI.cpp | 1 + Engine/Source/Runtime/RHI/Public/DynamicRHI.h | 11 +- Engine/Source/Runtime/RHI/Public/RHI.h | 4 + .../Runtime/RHI/Public/RHICommandList.h | 14 +- .../Runtime/RHI/Public/RHIDefinitions.h | 2 + .../RenderCore/Private/RenderUtils.cpp | 1 + .../Renderer/Private/AtmosphereRendering.cpp | 3 + .../Renderer/Private/BasePassRendering.cpp | 3 + .../Renderer/Private/BasePassRendering.h | 4 + .../Private/CapsuleShadowRendering.cpp | 5 + .../CompositionLighting.cpp | 10 + .../PostProcessDeferredDecals.cpp | 175 +- .../PostProcessDeferredDecals.h | 12 +- .../Private/DeferredShadingRenderer.cpp | 14 +- .../Renderer/Private/DepthRendering.cpp | 19 +- .../Renderer/Private/DistortionRendering.cpp | 3 + .../Runtime/Renderer/Private/FogRendering.cpp | 3 + .../Private/LightPropagationVolume.cpp | 6 +- .../Renderer/Private/LightRendering.cpp | 3 + .../Private/MobileBasePassRendering.h | 4 + .../Private/PostProcess/RenderTargetPool.cpp | 7 + .../PostProcess/SceneRenderTargets.cpp | 20 +- .../Private/PostProcess/SceneRenderTargets.h | 1 + .../PostProcess/ScreenSpaceReflections.cpp | 4 + .../Private/ReflectionEnvironment.cpp | 5 + .../Renderer/Private/RendererScene.cpp | 2 +- .../Private/SceneCaptureRendering.cpp | 15 +- .../Renderer/Private/SceneRendering.cpp | 8 + .../Renderer/Private/SceneVisibility.cpp | 5 +- .../Renderer/Private/ShadowDepthRendering.cpp | 3 + .../Renderer/Private/ShadowRendering.cpp | 3 + .../Renderer/Private/ShadowRendering.h | 15 +- .../Renderer/Private/TranslucentLighting.cpp | 9 + .../Renderer/Private/TranslucentRendering.cpp | 4 + .../Renderer/Private/VelocityRendering.cpp | 3 + .../Renderer/Public/RendererInterface.h | 10 +- .../Public/SceneRenderTargetParameters.h | 1 + .../Runtime/ShaderCore/Private/ShaderCore.cpp | 5 +- .../ShaderCore/Public/CrossCompilerCommon.h | 16 + .../Private/SlateMaterialShader.cpp | 4 + .../Private/SlateRHIRenderer.cpp | 3 + .../VulkanRHI/Private/VulkanCommandWrappers.h | 24 +- .../VulkanRHI/Private/VulkanCommands.cpp | 16 +- .../Runtime/VulkanRHI/Private/VulkanDebug.cpp | 2086 ++++++++++------- .../VulkanRHI/Private/VulkanDevice.cpp | 3 + .../VulkanRHI/Private/VulkanLayers.cpp | 50 +- .../VulkanRHI/Private/VulkanPendingState.cpp | 12 +- .../Runtime/VulkanRHI/Private/VulkanQuery.cpp | 30 +- .../Runtime/VulkanRHI/Private/VulkanQueue.cpp | 5 +- .../Runtime/VulkanRHI/Private/VulkanRHI.cpp | 2 +- .../VulkanRHI/Private/VulkanRHIPrivate.h | 2 + .../VulkanRHI/Private/VulkanRenderTarget.cpp | 13 +- .../VulkanRHI/Private/VulkanShaders.cpp | 42 +- .../VulkanRHI/Private/VulkanSwapChain.cpp | 5 +- .../VulkanRHI/Private/VulkanTexture.cpp | 12 +- .../Runtime/VulkanRHI/Private/VulkanUtil.cpp | 2 + .../VulkanRHI/Private/VulkanViewport.cpp | 33 +- .../Runtime/VulkanRHI/Public/VulkanRHI.h | 4 +- .../VulkanRHI/Public/VulkanResources.h | 11 +- .../VulkanRHI/Public/VulkanShaderResources.h | 8 +- .../Windows/D3D11RHI/Private/D3D11Device.cpp | 9 + .../D3D12RHI/Private/D3D12Commands.cpp | 3 + .../Windows/D3D12RHI/Private/D3D12Device.cpp | 1 + .../Windows/D3D12RHI/Private/D3D12Query.cpp | 20 +- .../Windows/D3D12RHI/Private/D3D12Query.h | 3 + 155 files changed, 3815 insertions(+), 1761 deletions(-) create mode 100644 Engine/Shaders/RTWriteMaskDecode.usf delete mode 100644 Engine/Source/Editor/NiagaraEditor/Private/NiagaraNodeConstant.cpp delete mode 100644 Engine/Source/Editor/NiagaraEditor/Private/NiagaraNodeGetAttr.cpp delete mode 100644 Engine/Source/Editor/NiagaraEditor/Private/NiagaraNodeOutputUpdate.cpp delete mode 100644 Engine/Source/Editor/NiagaraEditor/Public/NiagaraNodeConstant.h delete mode 100644 Engine/Source/Editor/NiagaraEditor/Public/NiagaraNodeGetAttr.h delete mode 100644 Engine/Source/Editor/NiagaraEditor/Public/NiagaraNodeOutputUpdate.h create mode 100644 Engine/Source/Runtime/Niagara/Private/NiagaraCommon.cpp diff --git a/Engine/Config/BaseInput.ini b/Engine/Config/BaseInput.ini index f85152445adc..cdc20b3bdc85 100644 --- a/Engine/Config/BaseInput.ini +++ b/Engine/Config/BaseInput.ini @@ -97,6 +97,7 @@ MaxScrollbackSize=1024 +ManualAutoCompleteList=(Command="Stat PHYSICS",Desc="Displays physics performance stats") +ManualAutoCompleteList=(Command="Stat STREAMING",Desc="Displays basic texture streaming stats") +ManualAutoCompleteList=(Command="Stat STREAMINGDETAILS",Desc="Displays detailed texture streaming stats") ++ManualAutoCompleteList=(Command="Stat GPU",Desc="Displays GPU stats for the frame") +ManualAutoCompleteList=(Command="Stat COLLISION",Desc=) +ManualAutoCompleteList=(Command="Stat PARTICLES",Desc=) +ManualAutoCompleteList=(Command="Stat SCRIPT",Desc=) diff --git a/Engine/Plugins/2D/Paper2D/Source/Paper2DEditor/Private/SpriteEditor/SpriteEditorViewportClient.cpp b/Engine/Plugins/2D/Paper2D/Source/Paper2DEditor/Private/SpriteEditor/SpriteEditorViewportClient.cpp index 2f99155637b6..46e5635301df 100644 --- a/Engine/Plugins/2D/Paper2D/Source/Paper2DEditor/Private/SpriteEditor/SpriteEditorViewportClient.cpp +++ b/Engine/Plugins/2D/Paper2D/Source/Paper2DEditor/Private/SpriteEditor/SpriteEditorViewportClient.cpp @@ -362,6 +362,7 @@ void FSpriteEditorViewportClient::AnalyzeSpriteMaterialType(UPaperSprite* Sprite case EBlendMode::BLEND_Translucent: case EBlendMode::BLEND_Additive: case EBlendMode::BLEND_Modulate: + case EBlendMode::BLEND_AlphaComposite: NumTranslucentTriangles += NumTriangles; break; case EBlendMode::BLEND_Masked: diff --git a/Engine/Plugins/2D/Paper2D/Source/Paper2DEditor/Private/TileMapEditing/TileMapEditorViewportClient.cpp b/Engine/Plugins/2D/Paper2D/Source/Paper2DEditor/Private/TileMapEditing/TileMapEditorViewportClient.cpp index 516a955343f7..041e348d0f67 100644 --- a/Engine/Plugins/2D/Paper2D/Source/Paper2DEditor/Private/TileMapEditing/TileMapEditorViewportClient.cpp +++ b/Engine/Plugins/2D/Paper2D/Source/Paper2DEditor/Private/TileMapEditing/TileMapEditorViewportClient.cpp @@ -189,6 +189,7 @@ void FTileMapEditorViewportClient::DrawCanvas(FViewport& InViewport, FSceneView& case EBlendMode::BLEND_Translucent: case EBlendMode::BLEND_Additive: case EBlendMode::BLEND_Modulate: + case EBlendMode::BLEND_AlphaComposite: MaterialType = Translucent; break; case EBlendMode::BLEND_Masked: diff --git a/Engine/Shaders/BasePassPixelShader.usf b/Engine/Shaders/BasePassPixelShader.usf index de3cee972c50..75b6df7be106 100644 --- a/Engine/Shaders/BasePassPixelShader.usf +++ b/Engine/Shaders/BasePassPixelShader.usf @@ -46,6 +46,10 @@ SamplerState HZBSampler; Texture2D PrevSceneColor; SamplerState PrevSceneColorSampler; +#if PLATFORM_SUPPORTS_RENDERTARGET_WRITE_MASK && USE_DBUFFER && MATERIALDECALRESPONSEMASK && !MATERIALBLENDING_ANY_TRANSLUCENT + Texture2D DBufferMask; +#endif + #ifndef COMPILER_GLSL #define COMPILER_GLSL 0 #endif @@ -789,18 +793,26 @@ void FPixelShaderInOut_MainPS( #endif if(Primitive.DecalReceiverMask > 0 && View.ShowDecalsMask > 0) { - float2 NDC = MaterialParameters.ScreenPosition.xy / MaterialParameters.ScreenPosition.w; - - float2 ScreenUV = NDC * View.ScreenPositionScaleBias.xy + View.ScreenPositionScaleBias.wz; - - FDBufferData DBufferData = GetDBufferData(ScreenUV); - // the material can disable the DBuffer effects for better performance or control - if((MATERIALDECALRESPONSEMASK & 0x1) == 0) { DBufferData.PreMulColor = 0; DBufferData.ColorOpacity = 1; } - if((MATERIALDECALRESPONSEMASK & 0x2) == 0) { DBufferData.PreMulWorldNormal = 0; DBufferData.NormalOpacity = 1; } - if((MATERIALDECALRESPONSEMASK & 0x4) == 0) { DBufferData.PreMulRoughness = 0; DBufferData.RoughnessOpacity = 1; } + #if PLATFORM_SUPPORTS_RENDERTARGET_WRITE_MASK + uint RTWriteMaskBit = DecodeRTWriteMaskTexture(In.SvPosition.xy, DBufferMask); + if(RTWriteMaskBit) + #endif + { + float2 NDC = MaterialParameters.ScreenPosition.xy / MaterialParameters.ScreenPosition.w; - ApplyDBufferData(DBufferData, MaterialParameters.WorldNormal, SubsurfaceColor, Roughness, BaseColor, Metallic, Specular); + // Note: We are using View and not ResolvedView here. + // It has the correct ScreenPositionScaleBias values for screen space compositing. + float2 ScreenUV = NDC * View.ScreenPositionScaleBias.xy + View.ScreenPositionScaleBias.wz; + + FDBufferData DBufferData = GetDBufferData(ScreenUV); + + // the material can disable the DBuffer effects for better performance or control + if((MATERIALDECALRESPONSEMASK & 0x1) == 0) { DBufferData.PreMulColor = 0; DBufferData.ColorOpacity = 1; } + if((MATERIALDECALRESPONSEMASK & 0x2) == 0) { DBufferData.PreMulWorldNormal = 0; DBufferData.NormalOpacity = 1; } + if((MATERIALDECALRESPONSEMASK & 0x4) == 0) { DBufferData.PreMulRoughness = 0; DBufferData.RoughnessOpacity = 1; } + ApplyDBufferData(DBufferData, MaterialParameters.WorldNormal, SubsurfaceColor, Roughness, BaseColor, Metallic, Specular); + } } #endif diff --git a/Engine/Shaders/Common.usf b/Engine/Shaders/Common.usf index 1ea64ebc5a71..c69ccdb154f4 100644 --- a/Engine/Shaders/Common.usf +++ b/Engine/Shaders/Common.usf @@ -954,6 +954,24 @@ MaterialFloat3 Decode32BPPHDR(MaterialFloat4 Encoded, MaterialFloat3 OtherEncode } } + +/** Get render target write mask value + * This gets a bit from a write mask texture created with FRTWriteMaskDecodeCS. Only supprted on some platforms. + */ +#if PLATFORM_SUPPORTS_RENDERTARGET_WRITE_MASK +uint DecodeRTWriteMaskTexture(in float2 ScreenPosition, in Texture2D RTWriteMaskTexture) +{ + int2 IntPosition = int2(ScreenPosition.xy); + uint RTWriteMaskValue = RTWriteMaskTexture.Load( int3(IntPosition.x/8, IntPosition.y/8, 0) ); + + int2 BitCoord = ((IntPosition / int2(4, 4)) % int2(2, 2)); + uint BitIdx = BitCoord.x + (BitCoord.y*2); + uint RTWriteMaskBit = RTWriteMaskValue & (1<>) +// ~10 ALU operations for result.xy (8 mad, 2 >>) +// ~12 ALU operations for result.xyz (9 mad, 3 >>) +uint3 Rand3DPCG16(int3 p) +{ + // taking a signed int then reinterpreting as unsigned gives good behavior for negatives + uint3 v = uint3(p); + + // Linear congruential step. These LCG constants are from Numerical Recipies + // For additional #'s, PCG would do multiple LCG steps and scramble each on output + // So v here is the RNG state + v = v * 1664525u + 1013904223u; + + // PCG uses xorshift for the final shuffle, but it is expensive (and cheap + // versions of xorshift have visible artifacts). Instead, use simple MAD Feistel steps + // + // Feistel ciphers divide the state into separate parts (usually by bits) + // then apply a series of permutation steps one part at a time. The permutations + // use a reversible operation (usually ^) to part being updated with the result of + // a permutation function on the other parts and the key. + // + // In this case, I'm using v.x, v.y and v.z as the parts, using + instead of ^ for + // the combination function, and just multiplying the other two parts (no key) for + // the permutation function. + // + // That gives a simple mad per round. + v.x += v.y*v.z; + v.y += v.z*v.x; + v.z += v.x*v.y; + v.x += v.y*v.z; + v.y += v.z*v.x; + v.z += v.x*v.y; + + // only top 16 bits are well shuffled + return v >> 16u; +} + +// 3D random number generator inspired by PCGs (permuted congruential generator) +// Using a **simple** Feistel cipher in place of the usual xor shift permutation step +// @param v = 3D integer coordinate +// @return three elements w/ 16 random bits each (0-0xffff). +// ~12 ALU operations for result.x (10 mad, 3 >>) +// ~14 ALU operations for result.xy (11 mad, 3 >>) +// ~15 ALU operations for result.xyz (12 mad, 3 >>) +uint3 Rand3DPCG32(int3 p) +{ + // taking a signed int then reinterpreting as unsigned gives good behavior for negatives + uint3 v = uint3(p); + + // Linear congruential step. + v = v * 1664525u + 1013904223u; + + // swapping low and high bits makes all 32 bits pretty good + v = v * (1u << 16u) + (v >> 16u); + + // final shuffle + v.x += v.y*v.z; + v.y += v.z*v.x; + v.z += v.x*v.y; + v.x += v.y*v.z; + v.y += v.z*v.x; + v.z += v.x*v.y; + + return v; +} + /** * Find good arbitrary axis vectors to represent U and V axes of a plane, * given just the normal. Ported from UnMath.h @@ -189,7 +260,7 @@ float4 PerlinRamp(float4 t) float MGradient(uint seed, float3 offset) { uint rand = RandBBSuint24(seed); - float3 direction = float3((rand & 1) << 1, (rand & 2), (rand & 4) >> 1) - 1; + float3 direction = float3(rand & 1, rand & 2, rand & 4) * float3(2, 1, 0.5) - 1; return dot(direction, offset); } @@ -271,14 +342,14 @@ float ValueNoise3D_ALU(float3 v, bool bTiling, float RepeatSize) float seed000, seed001, seed010, seed011, seed100, seed101, seed110, seed111; float3 fv = NoiseSeeds(v, bTiling, RepeatSize, seed000, seed001, seed010, seed011, seed100, seed101, seed110, seed111); - float rand000 = RandBBSfloat(seed000 / BBS_PRIME24) * 2 - 1; - float rand100 = RandBBSfloat(seed100 / BBS_PRIME24) * 2 - 1; - float rand010 = RandBBSfloat(seed010 / BBS_PRIME24) * 2 - 1; - float rand110 = RandBBSfloat(seed110 / BBS_PRIME24) * 2 - 1; - float rand001 = RandBBSfloat(seed001 / BBS_PRIME24) * 2 - 1; - float rand101 = RandBBSfloat(seed101 / BBS_PRIME24) * 2 - 1; - float rand011 = RandBBSfloat(seed011 / BBS_PRIME24) * 2 - 1; - float rand111 = RandBBSfloat(seed111 / BBS_PRIME24) * 2 - 1; + float rand000 = RandBBSfloat(seed000) * 2 - 1; + float rand100 = RandBBSfloat(seed100) * 2 - 1; + float rand010 = RandBBSfloat(seed010) * 2 - 1; + float rand110 = RandBBSfloat(seed110) * 2 - 1; + float rand001 = RandBBSfloat(seed001) * 2 - 1; + float rand101 = RandBBSfloat(seed101) * 2 - 1; + float rand011 = RandBBSfloat(seed011) * 2 - 1; + float rand111 = RandBBSfloat(seed111) * 2 - 1; float3 Weights = PerlinRamp(float4(fv, 0)).xyz; @@ -386,6 +457,115 @@ float FastGradientPerlinNoise3D_TEX(float3 xyz) return dot(xyz, n) - d; } + +// 3D jitter offset within a voronoi noise cell +// @param pos - integer lattice corner +// @return random offsets vector +float3 VoronoiCornerSample(int3 pos, int Quality) +{ + // random values in [-0.5, 0.5] + float3 noise = float3(Rand3DPCG16(pos)) / 0xffff - 0.5; + + // quality level 1 or 2: searches a 2x2x2 neighborhood with points distributed on a sphere + // scale factor to guarantee jittered points will be found within a 2x2x2 search + if (Quality <= 2) + { + return normalize(noise) * 0.2588; + } + + // quality level 3: searches a 3x3x3 neighborhood with points distributed on a sphere + // scale factor to guarantee jittered points will be found within a 3x3x3 search + if (Quality == 3) + { + return normalize(noise) * 0.3090; + } + + // quality level 4: jitter to anywhere in the cell, needs 4x4x4 search + return noise; +} + +// 220 instruction Worley noise +float VoronoiNoise3D_ALU(float3 v, int Quality, bool bTiling, float RepeatSize) +{ + float3 fv = frac(v), fv2 = frac(v + 0.5); + float3 iv = floor(v), iv2 = floor(v + 0.5); + + // with initial minimum distance = infinity (or at least bigger than 4), first min is optimized away + float mindist = 100; + float3 offset; + + // quality level 3: do 3x3x3 search centered on current location + if (Quality == 3) + { + float3 mincell = floor(v - 1), maxcell = floor(v + 1); + float3 cell; + LOOP for (cell.x = mincell.x; cell.x <= maxcell.x; ++cell.x) + { + LOOP for (cell.y = mincell.y; cell.y <= maxcell.y; ++cell.y) + { + LOOP for (cell.z = mincell.z; cell.z <= maxcell.z; ++cell.z) + { + float3 p = v - cell - VoronoiCornerSample(NoiseTileWrap(cell, bTiling, RepeatSize), Quality); + mindist = min(mindist, dot(p, p)); + } + } + } + } + + // all others, do 2x2x2 search (unrolled) + else + { + UNROLL for (offset.x = 0; offset.x <= 1; ++offset.x) + { + UNROLL for (offset.y = 0; offset.y <= 1; ++offset.y) + { + UNROLL for (offset.z = 0; offset.z <= 1; ++offset.z) + { + float3 p = fv - offset - VoronoiCornerSample(NoiseTileWrap(iv + offset, bTiling, RepeatSize), Quality); + mindist = min(mindist, dot(p, p)); + // quality level 2, do extra set of points, offset by half a cell + if (Quality == 2) + { + // 467 is just an offset to a different area in the random number field to avoid similar neighbor artifacts + p = fv2 - offset - VoronoiCornerSample(NoiseTileWrap(iv2 + offset, bTiling, RepeatSize) + 467, Quality); + mindist = min(mindist, dot(p, p)); + } + } + } + } + } + + // quality level 4: add extra sets of four cells in each direction + if (Quality >= 4) + { + float3 p; + UNROLL for (offset.x = -1; offset.x <= 2; offset.x += 3) + { + UNROLL for (offset.y = 0; offset.y <= 1; ++offset.y) + { + UNROLL for (offset.z = 0; offset.z <= 1; ++offset.z) + { + // along x axis + p = fv - offset.xyz - VoronoiCornerSample(NoiseTileWrap(iv + offset.xyz, bTiling, RepeatSize), Quality); + mindist = min(mindist, dot(p, p)); + + // along y axis + p = fv - offset.yzx - VoronoiCornerSample(NoiseTileWrap(iv + offset.yzx, bTiling, RepeatSize), Quality); + mindist = min(mindist, dot(p, p)); + + // along z axis + p = fv - offset.zxy - VoronoiCornerSample(NoiseTileWrap(iv + offset.zxy, bTiling, RepeatSize), Quality); + mindist = min(mindist, dot(p, p)); + } + } + } + } + + // transform to -1 to 1 range as expected by later OutputMin to OutputMax transform + return (sqrt(mindist) * 2 ) - 1; +} + + // -------- Simplex method (faster in higher dimensions because less samples are used, uses gradient noise for quality) --------- // D:/ 1D:2, 2D:4/3, 3D:8/4, 4D:16/5 diff --git a/Engine/Shaders/SimpleElementPixelShader.usf b/Engine/Shaders/SimpleElementPixelShader.usf index 267d29adb463..9de43ae1d4d9 100644 --- a/Engine/Shaders/SimpleElementPixelShader.usf +++ b/Engine/Shaders/SimpleElementPixelShader.usf @@ -71,6 +71,10 @@ float3 SimpleElementFrameBufferBlendOp(float4 Source) #if SE_BLEND_MODE == SE_BLEND_OPAQUE || SE_BLEND_MODE == SE_BLEND_MASKED || SE_BLEND_MODE == SE_BLEND_MASKEDDISTANCEFIELD || SE_BLEND_MODE == SE_BLEND_MASKEDDISTANCEFIELDSHADOWED return Source.rgb; +// AlphaComposite will set both MATERIALBLENDING_TRANSLUCENT and MATERIALBLENDING_ALPHACOMPOSITE defines +// so ensure MATERIALBLENDING_ALPHACOMPOSITE gets first in line +#elif MATERIALBLENDING_ALPHACOMPOSITE + return Source.rgb + (Dest.rgb*(1.0 - Source.a)); #elif SE_BLEND_MODE == SE_BLEND_TRANSLUCENT || SE_BLEND_MODE == SE_BLEND_TRANSLUCENTALPHAONLY || SE_BLEND_MODE == SE_BLEND_ALPHABLEND || SE_BLEND_MODE == SE_BLEND_TRANSLUCENTDISTANCEFIELD || SE_BLEND_MODE == SE_BLEND_TRANSLUCENTDISTANCEFIELDSHADOWED return (Source.rgb*Source.a) + (Dest.rgb*(1.0 - Source.a)); #elif SE_BLEND_MODE == SE_BLEND_ADDITIVE diff --git a/Engine/Shaders/VulkanCommon.usf b/Engine/Shaders/VulkanCommon.usf index 2683616b381d..71e7fdf76a9c 100644 --- a/Engine/Shaders/VulkanCommon.usf +++ b/Engine/Shaders/VulkanCommon.usf @@ -5,6 +5,6 @@ =============================================================================*/ // Update this GUID to improve shader recompilation for Vulkan only shaders -// GUID = 864401E6-0B37-40F0-850F-E5B79A6FEF56 +// GUID = 864401E6-0B37-40F0-850F-E5B79A6FEF68 #pragma once diff --git a/Engine/Source/Developer/MaterialUtilities/Private/MaterialUtilities.cpp b/Engine/Source/Developer/MaterialUtilities/Private/MaterialUtilities.cpp index b3e9ff736a40..5d568b1287a8 100644 --- a/Engine/Source/Developer/MaterialUtilities/Private/MaterialUtilities.cpp +++ b/Engine/Source/Developer/MaterialUtilities/Private/MaterialUtilities.cpp @@ -1751,7 +1751,98 @@ static bool GetUniformScale(const TArray Scales, float& UniformScale) return false; } -bool FMaterialUtilities::ExportMaterialTexCoordScales(UMaterialInterface* InMaterial, EMaterialQualityLevel::Type QualityLevel, ERHIFeatureLevel::Type FeatureLevel, TArray& OutScales) +uint32 GetTypeHash(const FMaterialUtilities::FExportErrorManager::FError& Error) +{ + return GetTypeHash(Error.Material); +} + +bool FMaterialUtilities::FExportErrorManager::FError::operator==(const FError& Rhs) const +{ + return Material == Rhs.Material && RegisterIndex == Rhs.RegisterIndex && ErrorType == Rhs.ErrorType; +} + + +void FMaterialUtilities::FExportErrorManager::Register(const UMaterialInterface* Material, const UTexture* Texture, int32 RegisterIndex, EErrorType ErrorType) +{ + if (!Material || !Texture) return; + + FError Error; + Error.Material = Material->GetMaterialResource(FeatureLevel); + if (!Error.Material) return; + Error.RegisterIndex = RegisterIndex; + Error.ErrorType = ErrorType; + + FInstance Instance; + Instance.Material = Material; + Instance.Texture = Texture; + + ErrorInstances.FindOrAdd(Error).Push(Instance); +} + +void FMaterialUtilities::FExportErrorManager::OutputToLog() +{ + const UMaterialInterface* CurrentMaterial = nullptr; + int32 MaxInstanceCount = 0; + FString TextureErrors; + + for (TMap >::TIterator It(ErrorInstances);; ++It) + { + if (It && !It->Value.Num()) continue; + + // Here we pack texture list per material. + if (!It || CurrentMaterial != It->Value[0].Material) + { + // Flush + if (CurrentMaterial) + { + FString SimilarCount(TEXT("")); + if (MaxInstanceCount > 1) + { + SimilarCount = FString::Printf(TEXT(", %d similar"), MaxInstanceCount - 1); + } + + if (CurrentMaterial == CurrentMaterial->GetMaterial()) + { + UE_LOG(LogMaterialUtilities, Warning, TEXT("Error generating scales for %s%s: %s"), *CurrentMaterial->GetName(), *SimilarCount, *TextureErrors); + } + else + { + UE_LOG(LogMaterialUtilities, Warning, TEXT("Error generating scales for %s, UMaterial=%s%s: %s"), *CurrentMaterial->GetName(), *CurrentMaterial->GetMaterial()->GetName(), *SimilarCount, *TextureErrors); + } + } + + // Exit + if (!It) + { + break; + } + + // Start new + CurrentMaterial = It->Value[0].Material; + MaxInstanceCount = It->Value.Num(); + TextureErrors.Empty(); + } + else + { + // Append + MaxInstanceCount = FMath::Max(MaxInstanceCount, It->Value.Num()); + } + + const TCHAR* ErrorMsg = TEXT("Unkown Error"); + if (It->Key.ErrorType == EET_IncohorentValues) + { + ErrorMsg = TEXT("Incoherent"); + } + else if (It->Key.ErrorType == EET_NoValues) + { + ErrorMsg = TEXT("NoValues"); + } + + TextureErrors.Append(FString::Printf(TEXT("(%s:%d,%s) "), ErrorMsg, It->Key.RegisterIndex, *It->Value[0].Texture->GetName())); + } +} + +bool FMaterialUtilities::ExportMaterialTexCoordScales(UMaterialInterface* InMaterial, EMaterialQualityLevel::Type QualityLevel, ERHIFeatureLevel::Type FeatureLevel, TArray& OutScales, FExportErrorManager& OutErrors) { TArray RenderedVectors; @@ -1905,21 +1996,7 @@ bool FMaterialUtilities::ExportMaterialTexCoordScales(UMaterialInterface* InMate } } - if (FailedTexture) - { - if (TextureIndexScales.Num()) - { - // Cause 1 : the output does not map to an actual uniform scale. - // Cause 2 : the alogrithm fails to find the scale value (even though it is somewhat there). - UE_LOG(LogMaterialUtilities, Warning, TEXT("ExportMaterialTexCoordScales: Failed to find constant scale for texture index %d of material %s (bound to texture %s)"), RegisterIndex, *InMaterial->GetName(), *FailedTexture->GetName()); - } - else - { - // Cause 1: the shader did not use this texture at all, resulting in value being the default value (could be because of some branching) - // Cause 2: the shader outputs the scale, but the scale was 0. That means the coordinate did not change between the pixels. For instance, if the mapping was based on the world position. - UE_LOG(LogMaterialUtilities, Warning, TEXT("ExportMaterialTexCoordScales: Failed to generate scales for texture index %d of material %s (bound to texture %s)"), RegisterIndex, *InMaterial->GetName(), *FailedTexture->GetName()); - } - } + OutErrors.Register(InMaterial, FailedTexture, RegisterIndex, TextureIndexScales.Num() ? FExportErrorManager::EErrorType::EET_IncohorentValues : FExportErrorManager::EErrorType::EET_NoValues); } } diff --git a/Engine/Source/Developer/MaterialUtilities/Public/MaterialUtilities.h b/Engine/Source/Developer/MaterialUtilities/Public/MaterialUtilities.h index 9517dc415cac..8ab04e19c027 100644 --- a/Engine/Source/Developer/MaterialUtilities/Public/MaterialUtilities.h +++ b/Engine/Source/Developer/MaterialUtilities/Public/MaterialUtilities.h @@ -378,6 +378,61 @@ public: */ static void ResizeFlattenMaterial(FFlattenMaterial& InFlattenMaterial, const struct FMeshProxySettings& InMeshProxySettings); + + /** + * Contains errors generated when exporting material texcoord scales. + * Used to prevent displaying duplicates, as instances using the same shaders get the same issues. + */ + class MATERIALUTILITIES_API FExportErrorManager + { + public: + + FExportErrorManager(ERHIFeatureLevel::Type InFeatureLevel) : FeatureLevel(InFeatureLevel) {} + + enum EErrorType + { + EET_IncohorentValues, + EET_NoValues + }; + + /** + * Register a new error. + * + * @param Material The material having this error. + * @param Texture The texture for which the scale could not be generated. + * @param RegisterIndex The register index bound to this texture. + * @param ErrorType The issue encountered. + */ + void Register(const UMaterialInterface* Material, const UTexture* Texture, int32 RegisterIndex, EErrorType ErrorType); + + /** + * Output all errors registered. + */ + void OutputToLog(); + + private: + + struct FError + { + const FMaterial* Material; + int32 RegisterIndex; + EErrorType ErrorType; + + bool operator==(const FError& Rhs) const; + }; + + struct FInstance + { + const UMaterialInterface* Material; + const UTexture* Texture; + }; + + friend uint32 GetTypeHash(const FError& Error); + + ERHIFeatureLevel::Type FeatureLevel; + TMap > ErrorInstances; + }; + /** * Get the material texcoord scales applied on each textures * @@ -387,7 +442,7 @@ public: * @param OutScales TheOutput array of rendered samples * @return Whether operation was successful */ - static bool ExportMaterialTexCoordScales(UMaterialInterface* InMaterial, EMaterialQualityLevel::Type QualityLevel, ERHIFeatureLevel::Type FeatureLevel, TArray& OutScales); + static bool ExportMaterialTexCoordScales(UMaterialInterface* InMaterial, EMaterialQualityLevel::Type QualityLevel, ERHIFeatureLevel::Type FeatureLevel, TArray& OutScales, FExportErrorManager& OutErrors); private: diff --git a/Engine/Source/Developer/MeshUtilities/Private/MeshUtilities.cpp b/Engine/Source/Developer/MeshUtilities/Private/MeshUtilities.cpp index db279802be71..54b4b1dacda2 100644 --- a/Engine/Source/Developer/MeshUtilities/Private/MeshUtilities.cpp +++ b/Engine/Source/Developer/MeshUtilities/Private/MeshUtilities.cpp @@ -5080,8 +5080,8 @@ bool FMeshUtilities::BuildSkeletalMesh_Legacy(FStaticLODModel& LODModel, const F SkeletalMeshTools::BuildSkeletalMeshChunks(Faces, RawVertices, VertIndexAndZ, bKeepOverlappingVertices, Chunks, bTooManyVerts); // Chunk vertices to satisfy the requested limit. - static const auto MaxBonesVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("Compat.MAX_GPUSKIN_BONES")); - const int32 MaxGPUSkinBones = MaxBonesVar->GetValueOnAnyThread(); + const uint32 MaxGPUSkinBones = FGPUBaseSkinVertexFactory::GetMaxGPUSkinBones(); + check(MaxGPUSkinBones <= FGPUBaseSkinVertexFactory::GHardwareMaxGPUSkinBones); SkeletalMeshTools::ChunkSkinnedVertices(Chunks, MaxGPUSkinBones); // Build the skeletal model from chunks. diff --git a/Engine/Source/Developer/VulkanShaderFormat/Private/VulkanBackend.cpp b/Engine/Source/Developer/VulkanShaderFormat/Private/VulkanBackend.cpp index d7944dd9edae..a7c8c051621e 100644 --- a/Engine/Source/Developer/VulkanShaderFormat/Private/VulkanBackend.cpp +++ b/Engine/Source/Developer/VulkanShaderFormat/Private/VulkanBackend.cpp @@ -36,6 +36,7 @@ #include "hlslcc_private.h" #include "VulkanBackend.h" #include "compiler.h" +#include "ShaderCompilerCommon.h" #include "VulkanConfiguration.h" @@ -49,6 +50,7 @@ PRAGMA_ENABLE_SHADOW_VARIABLE_WARNINGS #include "IRDump.h" //@todo-rco: Remove STL! #include +#include //#define OPTIMIZE_ANON_STRUCTURES_OUT // We can't optimize them out presently, because apparently Windows Radeon // OpenGL driver chokes on valid GLSL code then. @@ -57,7 +59,7 @@ PRAGMA_ENABLE_SHADOW_VARIABLE_WARNINGS #define _strdup strdup #endif -static inline std::string FixHlslName(const glsl_type* Type) +static inline std::string FixHlslName(const glsl_type* Type, bool bUseTextureInsteadOfSampler = false) { check(Type->is_image() || Type->is_vector() || Type->is_numeric() || Type->is_void() || Type->is_sampler() || Type->is_scalar()); std::string Name = Type->name; @@ -113,6 +115,25 @@ static inline std::string FixHlslName(const glsl_type* Type) { return "mat4"; } + else if (Type->is_sampler() && !Type->sampler_buffer && bUseTextureInsteadOfSampler) + { + if (!strcmp(Type->HlslName, "texturecube")) + { + return "textureCube"; + } + else if (!strcmp(Type->HlslName, "texture2d")) + { + return "texture2D"; + } + else if (!strcmp(Type->HlslName, "texture3d")) + { + return "texture3D"; + } + else + { + return Type->HlslName; + } + } return Name; } @@ -497,7 +518,7 @@ static inline EDescriptorSetStage GetDescriptorSetForStage(_mesa_glsl_parser_tar /** * IR visitor used to generate GLSL. Based on ir_print_visitor. */ -class vulkan_ir_gen_glsl_visitor : public ir_visitor +class FGenerateVulkanVisitor : public ir_visitor { /** Track which multi-dimensional arrays are used. */ struct md_array_entry : public exec_node @@ -552,7 +573,7 @@ class vulkan_ir_gen_glsl_visitor : public ir_visitor bool bIsES31; EHlslCompileTarget Target; _mesa_glsl_parser_targets ShaderTarget; - + FVulkanLanguageSpec* LanguageSpec; bool bGenerateLayoutLocations; bool bDefaultPrecisionIsHalf; @@ -587,6 +608,8 @@ class vulkan_ir_gen_glsl_visitor : public ir_visitor // Found dFdx or dFdy bool bUsesDXDY; + std::vector SamplerStateNames; + /** * Return true if the type is a multi-dimensional array. Also, track the * array. @@ -714,7 +737,7 @@ class vulkan_ir_gen_glsl_visitor : public ir_visitor } else { - std::string Name = FixHlslName(t); + std::string Name = FixHlslName(t, LanguageSpec->AllowsSharingSamplers()); ralloc_asprintf_append(buffer, "%s", Name.c_str()); } } @@ -819,18 +842,18 @@ class vulkan_ir_gen_glsl_visitor : public ir_visitor return GLSL_PRECISION_DEFAULT; } - void AppendPrecisionModifier(char** inBuffer, EPrecisionModifier PrecisionModifier) + const char* GetPrecisionModifierName(EPrecisionModifier PrecisionModifier) { switch (PrecisionModifier) { case GLSL_PRECISION_LOWP: - ralloc_asprintf_append(inBuffer, "lowp "); + return "lowp"; break; case GLSL_PRECISION_MEDIUMP: - ralloc_asprintf_append(inBuffer, "mediump "); + return "mediump"; break; case GLSL_PRECISION_HIGHP: - ralloc_asprintf_append(inBuffer, "highp "); + return "highp"; break; case GLSL_PRECISION_DEFAULT: break; @@ -838,6 +861,12 @@ class vulkan_ir_gen_glsl_visitor : public ir_visitor // we missed a type check(false); } + return ""; + } + + inline void AppendPrecisionModifier(char** inBuffer, EPrecisionModifier PrecisionModifier) + { + ralloc_asprintf_append(inBuffer, "%s ", GetPrecisionModifierName(PrecisionModifier)); } /** @@ -1057,21 +1086,25 @@ class vulkan_ir_gen_glsl_visitor : public ir_visitor } else { - char* layout = nullptr; + uint32 Interpolation = var->interpolation; if (var->type->is_sampler()) { layout = ralloc_asprintf(nullptr, "layout(set=%d, binding=%d) ", GetDescriptorSetForStage(ShaderTarget), - BindingTable.RegisterBinding(var->name, "s", var->type->sampler_buffer ? FVulkanBindingTable::TYPE_SAMPLER_BUFFER : FVulkanBindingTable::TYPE_SAMPLER)); + BindingTable.RegisterBinding(var->name, "s", var->type->sampler_buffer ? FVulkanBindingTable::TYPE_SAMPLER_BUFFER : FVulkanBindingTable::TYPE_COMBINED_IMAGE_SAMPLER)); } - - if (bGenerateLayoutLocations && var->explicit_location) + else if (bGenerateLayoutLocations && var->explicit_location) { check(layout_bits == 0); layout = ralloc_asprintf(nullptr, "layout(location=%d) ", var->location); + if (ShaderTarget == fragment_shader && var->type->is_integer() && var->mode == ir_var_in) + { + // Flat + Interpolation = 2; + } } ralloc_asprintf_append( @@ -1082,7 +1115,7 @@ class vulkan_ir_gen_glsl_visitor : public ir_visitor invariant_str[var->invariant], patch_constant_str[var->is_patch_constant], mode_str[var->mode], - interp_str[var->interpolation] + interp_str[Interpolation] ); if (bEmitPrecision) @@ -1120,7 +1153,6 @@ class vulkan_ir_gen_glsl_visitor : public ir_visitor // this is for the case of a variable that is declared, but not later dereferenced (which can happen // when debugging HLSLCC and running without optimization AddTypeToUsedStructs(var->type); - } virtual void visit(ir_function_signature *sig) @@ -1324,7 +1356,36 @@ class vulkan_ir_gen_glsl_visitor : public ir_visitor offset_str[tex->offset != 0], EXT_str[(int)bEmitEXT] ); - tex->sampler->accept(this); + + if (LanguageSpec->AllowsSharingSamplers() && !tex->sampler->type->sampler_buffer && tex->op != ir_txf) + { + uint32 SSIndex = AddUniqueSamplerState(tex->SamplerStateName); + char PackedName[256]; + sprintf_s(PackedName, "%sz%d", glsl_variable_tag_from_parser_target(ShaderTarget), SSIndex); + BindingTable.RegisterBinding(PackedName, "z", FVulkanBindingTable::TYPE_SAMPLER); + + auto GetSamplerSuffix = [](int32 Dim) + { + switch (Dim) + { + case GLSL_SAMPLER_DIM_1D: return "1D"; + case GLSL_SAMPLER_DIM_2D: return "2D"; + case GLSL_SAMPLER_DIM_3D: return "3D"; + case GLSL_SAMPLER_DIM_CUBE: return "Cube"; + //case GLSL_SAMPLER_DIM_RECT: return "Rect"; + //case GLSL_SAMPLER_DIM_BUF: return "Buf"; + default: return "INVALID"; + } + }; + + ralloc_asprintf_append(buffer, "sampler%s(", GetSamplerSuffix(tex->sampler->type->sampler_dimensionality)); + tex->sampler->accept(this); + ralloc_asprintf_append(buffer, ", %s)", PackedName); + } + else + { + tex->sampler->accept(this); + } // Emit coordinates. if ((op == ir_txs && tex->lod_info.lod) || op == ir_txm) @@ -2309,7 +2370,7 @@ class vulkan_ir_gen_glsl_visitor : public ir_visitor int32 Binding = BindingTable.RegisterBinding(block_name, var_name, Type); ralloc_asprintf_append( buffer, - "layout(set=%d, binding = %d, std140) uniform %s\n{\n", + "layout(set=%d, binding=%d, std140) uniform %s\n{\n", GetDescriptorSetForStage(ShaderTarget), Binding, block_name); @@ -2797,6 +2858,16 @@ class vulkan_ir_gen_glsl_visitor : public ir_visitor ralloc_asprintf_append(buffer, "\n"); } } + + if (!SamplerStateNames.empty()) + { + ralloc_asprintf_append(buffer, "// @SamplerStates: "); + for (uint32 Index = 0; Index < SamplerStateNames.size(); ++Index) + { + ralloc_asprintf_append(buffer, "%s%d:%s", Index > 0 ? "," : "", Index, SamplerStateNames[Index].c_str()); + } + ralloc_asprintf_append(buffer, "\n"); + } } /** @@ -2939,9 +3010,10 @@ class vulkan_ir_gen_glsl_visitor : public ir_visitor public: /** Constructor. */ - vulkan_ir_gen_glsl_visitor(EHlslCompileTarget InTarget, + FGenerateVulkanVisitor(EHlslCompileTarget InTarget, FVulkanBindingTable& InBindingTable, _mesa_glsl_parser_targets InShaderTarget, + FVulkanLanguageSpec* InLanguageSpec, bool bInGenerateLayoutLocations, bool bInDefaultPrecisionIsHalf) : early_depth_stencil(false) @@ -2950,6 +3022,7 @@ public: , wg_size_z(0) , Target(InTarget) , ShaderTarget(InShaderTarget) + , LanguageSpec(InLanguageSpec) , bGenerateLayoutLocations(bInGenerateLayoutLocations) , bDefaultPrecisionIsHalf(bInDefaultPrecisionIsHalf) , BindingTable(InBindingTable) @@ -2974,13 +3047,27 @@ public: } /** Destructor. */ - virtual ~vulkan_ir_gen_glsl_visitor() + virtual ~FGenerateVulkanVisitor() { hash_table_dtor(printable_names); hash_table_dtor(used_structures); hash_table_dtor(used_uniform_blocks); } + int32 AddUniqueSamplerState(const std::string& Name) + { + for (uint32 Index = 0; Index < SamplerStateNames.size(); ++Index) + { + if (SamplerStateNames[Index] == Name) + { + return (int32)Index; + } + } + + SamplerStateNames.push_back(Name); + return SamplerStateNames.size() - 1; + }; + /** * Executes the visitor on the provided ir. * @returns the GLSL source code generated. @@ -3000,10 +3087,12 @@ public: ralloc_asprintf_append(buffer, "precision %s float;\n", DefaultPrecision); ralloc_asprintf_append(buffer, "precision %s int;\n", DefaultPrecision); //ralloc_asprintf_append(buffer, "\n#ifndef DONTEMITSAMPLERDEFAULTPRECISION\n"); + ralloc_asprintf_append(buffer, "precision %s sampler;\n", DefaultPrecision); ralloc_asprintf_append(buffer, "precision %s sampler2D;\n", DefaultPrecision); ralloc_asprintf_append(buffer, "precision %s samplerCube;\n", DefaultPrecision); //ralloc_asprintf_append(buffer, "#endif\n"); } + // FramebufferFetchES2 'intrinsic' bool bUsesFramebufferFetchES2 = false;//UsesUEIntrinsic(ir, FRAMEBUFFER_FETCH_ES2); /* @@ -3126,6 +3215,55 @@ public: break; } } + + // Here since the code_buffer must have been populated beforehand + if (LanguageSpec->AllowsSharingSamplers()) + { + auto FindPrecision = [&](int32 Index) + { + for (auto& Pair : state->TextureToSamplerMap) + { + for (auto& Entry : Pair.second) + { + if (Entry == SamplerStateNames[Index]) + { + for (auto& PackedEntry : state->GlobalPackedArraysMap['s']) + { + if (!strcmp(Pair.first.c_str(), PackedEntry.Name.c_str())) + { + foreach_iter(exec_list_iterator, iter, sampler_variables) + { + ir_variable* var = ((extern_var*)iter.get())->var; + if (!strcmp(var->name, PackedEntry.CB_PackedSampler.c_str())) + { + return GetPrecisionModifierName(GetPrecisionModifier(var->type)); + } + } + } + } + } + } + } + + return ""; + }; + + const auto& Bindings = BindingTable.GetBindings(); + for (int32 Index = 0; Index < Bindings.Num(); ++Index) + { + if (Bindings[Index].Type == FVulkanBindingTable::TYPE_SAMPLER) + { + int32 Binding = atoi(Bindings[Index].Name + 2); + const char* Precision = FindPrecision(Binding); + + ralloc_asprintf_append(buffer, "layout(set=%d, binding=%d) uniform %s sampler %sz%d;\n", + GetDescriptorSetForStage(ShaderTarget), Index, + Precision, + glsl_variable_tag_from_parser_target(ShaderTarget), Binding); + } + } + } + buffer = 0; static const char* vulkan_required_extensions = @@ -3230,7 +3368,7 @@ struct FBreakPrecisionChangesVisitor : public ir_rvalue_visitor } }; -void vulkan_ir_gen_glsl_visitor::AddTypeToUsedStructs(const glsl_type* type) +void FGenerateVulkanVisitor::AddTypeToUsedStructs(const glsl_type* type) { if (type->base_type == GLSL_TYPE_STRUCT) { @@ -3274,7 +3412,7 @@ char* FVulkanCodeBackend::GenerateCode(exec_list* ir, _mesa_glsl_parse_state* st const bool bCanHaveUBs = true;//(HlslCompileFlags & HLSLCC_FlattenUniformBuffers) != HLSLCC_FlattenUniformBuffers; // Setup root visitor - vulkan_ir_gen_glsl_visitor visitor(Target, BindingTable, state->target, bGenerateLayoutLocations, bDefaultPrecisionIsHalf); + FGenerateVulkanVisitor visitor(Target, BindingTable, state->target, (FVulkanLanguageSpec*)state->LanguageSpec, bGenerateLayoutLocations, bDefaultPrecisionIsHalf); const char* code = visitor.run(ir, state, bGroupFlattenedUBs, bCanHaveUBs); @@ -5269,14 +5407,15 @@ void FVulkanCodeBackend::GenShaderPatchConstantFunctionInputs(_mesa_glsl_parse_s void FVulkanLanguageSpec::SetupLanguageIntrinsics(_mesa_glsl_parse_state* State, exec_list* ir) { +/* if (bIsES2) { make_intrinsic_genType(ir, State, FRAMEBUFFER_FETCH_ES2, ir_invalid_opcode, IR_INTRINSIC_FLOAT, 0, 4, 4); make_intrinsic_genType(ir, State, DEPTHBUFFER_FETCH_ES2, ir_invalid_opcode, IR_INTRINSIC_ALL_FLOATING, 3, 1, 1); make_intrinsic_genType(ir, State, GET_HDR_32BPP_HDR_ENCODE_MODE_ES2, ir_invalid_opcode, IR_INTRINSIC_ALL_FLOATING, 0); } - - if (State->language_version >= 310) +*/ + //if (State->language_version >= 310) { /** * Create GLSL functions that are left out of the symbol table @@ -5368,7 +5507,7 @@ FVulkanBindingTable::FBinding::FBinding(const char* InName, int32 InIndex, EBind FMemory::Memcpy(Name, InName, NewNameLength); // Validate Sampler type, s == PACKED_TYPENAME_SAMPLER - check((Type == TYPE_SAMPLER || Type == TYPE_SAMPLER_BUFFER) ? SubType == 's' : true); + check((Type == TYPE_COMBINED_IMAGE_SAMPLER || Type == TYPE_SAMPLER_BUFFER) ? SubType == 's' : true); check(Type == TYPE_PACKED_UNIFORM_BUFFER ? ( SubType == 'h' || SubType == 'm' || SubType == 'l' || SubType == 'i' || SubType == 'u' ) : true); diff --git a/Engine/Source/Developer/VulkanShaderFormat/Private/VulkanBackend.h b/Engine/Source/Developer/VulkanShaderFormat/Private/VulkanBackend.h index e6fa56c22909..9d8f0d097bd8 100644 --- a/Engine/Source/Developer/VulkanShaderFormat/Private/VulkanBackend.h +++ b/Engine/Source/Developer/VulkanShaderFormat/Private/VulkanBackend.h @@ -8,10 +8,12 @@ class FVulkanLanguageSpec : public ILanguageSpec { protected: - bool bIsES2; + bool bShareSamplers; public: - FVulkanLanguageSpec(bool bInIsES2) : bIsES2(bInIsES2) {} + FVulkanLanguageSpec(bool bInShareSamplers) + : bShareSamplers(bInShareSamplers) + {} virtual bool SupportsDeterminantIntrinsic() const override { @@ -32,13 +34,12 @@ public: virtual void SetupLanguageIntrinsics(_mesa_glsl_parse_state* State, exec_list* ir) override; - //#todo-rco: Enable - virtual bool AllowsSharingSamplers() const override { return false; } + virtual bool AllowsSharingSamplers() const override { return bShareSamplers; } }; class ir_variable; -// Generates GLSL compliant code from IR tokens +// Generates Vulkan compliant code from IR tokens #ifdef __GNUC__ #pragma GCC visibility push(default) #endif // __GNUC__ @@ -47,10 +48,12 @@ struct FVulkanBindingTable { enum EBindingType : uint16 { - TYPE_SAMPLER, + TYPE_COMBINED_IMAGE_SAMPLER, TYPE_SAMPLER_BUFFER, TYPE_UNIFORM_BUFFER, TYPE_PACKED_UNIFORM_BUFFER, + TYPE_SAMPLER, + TYPE_IMAGE, TYPE_MAX, }; diff --git a/Engine/Source/Developer/VulkanShaderFormat/Private/VulkanShaderCompiler.cpp b/Engine/Source/Developer/VulkanShaderFormat/Private/VulkanShaderCompiler.cpp index e3f608c5fdae..b18d47615be8 100644 --- a/Engine/Source/Developer/VulkanShaderFormat/Private/VulkanShaderCompiler.cpp +++ b/Engine/Source/Developer/VulkanShaderFormat/Private/VulkanShaderCompiler.cpp @@ -12,15 +12,15 @@ DEFINE_LOG_CATEGORY_STATIC(LogVulkanShaderCompiler, Log, All); -static int32 GUseExternalShaderCompiler = 0; -static FAutoConsoleVariableRef CVarVulkanUseExternalShaderCompiler( - TEXT("r.Vulkan.UseExternalShaderCompiler"), - GUseExternalShaderCompiler, - TEXT("Whether to use the internal shader compiling library or the external glslang tool.\n") - TEXT(" 0: Internal compiler\n") - TEXT(" 1: External compiler)"), - ECVF_Default - ); +//static int32 GUseExternalShaderCompiler = 0; +//static FAutoConsoleVariableRef CVarVulkanUseExternalShaderCompiler( +// TEXT("r.Vulkan.UseExternalShaderCompiler"), +// GUseExternalShaderCompiler, +// TEXT("Whether to use the internal shader compiling library or the external glslang tool.\n") +// TEXT(" 0: Internal compiler\n") +// TEXT(" 1: External compiler)"), +// ECVF_Default +// ); extern bool GenerateSpirv(const ANSICHAR* Source, FCompilerInfo& CompilerInfo, FString& OutErrors, const FString& DumpDebugInfoPath, TArray& OutSpirv); @@ -206,7 +206,7 @@ static inline FString GetExtension(EHlslShaderFrequency Frequency, bool bAddDot case HSF_DomainShader: Name = TEXT(".tese"); break; } - if (bAddDot) + if (!bAddDot) { ++Name; } @@ -239,15 +239,15 @@ static uint32 GetTypeComponents(const FString& Type) static void GenerateBindingTable(const FVulkanShaderSerializedBindings& SerializedBindings, FVulkanShaderBindingTable& OutBindingTable) { - int32 NumSamplers = 0; + int32 NumCombinedSamplers = 0; int32 NumSamplerBuffers = 0; int32 NumUniformBuffers = 0; auto& Layouts = SerializedBindings.Bindings; //#todo-rco: FIX! SamplerBuffers share numbering with Samplers - NumSamplers = Layouts[FVulkanShaderSerializedBindings::TYPE_SAMPLER].Num() + Layouts[FVulkanShaderSerializedBindings::TYPE_SAMPLER_BUFFER].Num(); - NumSamplerBuffers = Layouts[FVulkanShaderSerializedBindings::TYPE_SAMPLER].Num() + Layouts[FVulkanShaderSerializedBindings::TYPE_SAMPLER_BUFFER].Num(); + NumCombinedSamplers = Layouts[FVulkanShaderSerializedBindings::TYPE_COMBINED_IMAGE_SAMPLER].Num() + Layouts[FVulkanShaderSerializedBindings::TYPE_SAMPLER_BUFFER].Num(); + NumSamplerBuffers = Layouts[FVulkanShaderSerializedBindings::TYPE_COMBINED_IMAGE_SAMPLER].Num() + Layouts[FVulkanShaderSerializedBindings::TYPE_SAMPLER_BUFFER].Num(); NumUniformBuffers = Layouts[FVulkanShaderSerializedBindings::TYPE_PACKED_UNIFORM_BUFFER].Num() + Layouts[FVulkanShaderSerializedBindings::TYPE_UNIFORM_BUFFER].Num(); for (int32 Index = 0; Index < CrossCompiler::PACKED_TYPEINDEX_MAX; ++Index) @@ -255,15 +255,15 @@ static void GenerateBindingTable(const FVulkanShaderSerializedBindings& Serializ OutBindingTable.PackedGlobalUBsIndices[Index] = -1; } - OutBindingTable.SamplerBindingIndices.AddUninitialized(NumSamplers); + OutBindingTable.CombinedSamplerBindingIndices.AddUninitialized(NumCombinedSamplers); //#todo-rco: FIX! SamplerBuffers share numbering with Samplers OutBindingTable.SamplerBufferBindingIndices.AddUninitialized(NumSamplerBuffers); OutBindingTable.UniformBufferBindingIndices.AddUninitialized(NumUniformBuffers); - for (int32 Index = 0; Index < Layouts[FVulkanShaderSerializedBindings::TYPE_SAMPLER].Num(); ++Index) + for (int32 Index = 0; Index < Layouts[FVulkanShaderSerializedBindings::TYPE_COMBINED_IMAGE_SAMPLER].Num(); ++Index) { - auto& Mapping = Layouts[FVulkanShaderSerializedBindings::TYPE_SAMPLER][Index]; - OutBindingTable.SamplerBindingIndices[Mapping.EngineBindingIndex] = Mapping.VulkanBindingIndex; + auto& Mapping = Layouts[FVulkanShaderSerializedBindings::TYPE_COMBINED_IMAGE_SAMPLER][Index]; + OutBindingTable.CombinedSamplerBindingIndices[Mapping.EngineBindingIndex] = Mapping.VulkanBindingIndex; //#todo-rco: FIX! SamplerBuffers share numbering with Samplers OutBindingTable.SamplerBufferBindingIndices[Mapping.EngineBindingIndex] = Mapping.VulkanBindingIndex; } @@ -271,7 +271,7 @@ static void GenerateBindingTable(const FVulkanShaderSerializedBindings& Serializ for (int32 Index = 0; Index < Layouts[FVulkanShaderSerializedBindings::TYPE_SAMPLER_BUFFER].Num(); ++Index) { auto& Mapping = Layouts[FVulkanShaderSerializedBindings::TYPE_SAMPLER_BUFFER][Index]; - OutBindingTable.SamplerBindingIndices[Mapping.EngineBindingIndex] = Mapping.VulkanBindingIndex; + OutBindingTable.CombinedSamplerBindingIndices[Mapping.EngineBindingIndex] = Mapping.VulkanBindingIndex; //#todo-rco: FIX! SamplerBuffers share numbering with Samplers OutBindingTable.SamplerBufferBindingIndices[Mapping.EngineBindingIndex] = Mapping.VulkanBindingIndex; } @@ -292,7 +292,7 @@ static void GenerateBindingTable(const FVulkanShaderSerializedBindings& Serializ } // Do not share numbers here - OutBindingTable.NumDescriptorsWithoutPackedUniformBuffers = Layouts[FVulkanShaderSerializedBindings::TYPE_SAMPLER].Num() + Layouts[FVulkanShaderSerializedBindings::TYPE_SAMPLER_BUFFER].Num() + Layouts[FVulkanShaderSerializedBindings::TYPE_UNIFORM_BUFFER].Num(); + OutBindingTable.NumDescriptorsWithoutPackedUniformBuffers = Layouts[FVulkanShaderSerializedBindings::TYPE_COMBINED_IMAGE_SAMPLER].Num() + Layouts[FVulkanShaderSerializedBindings::TYPE_SAMPLER_BUFFER].Num() + Layouts[FVulkanShaderSerializedBindings::TYPE_UNIFORM_BUFFER].Num(); OutBindingTable.NumDescriptors = OutBindingTable.NumDescriptorsWithoutPackedUniformBuffers + Layouts[FVulkanShaderSerializedBindings::TYPE_PACKED_UNIFORM_BUFFER].Num(); } @@ -415,8 +415,11 @@ static void BuildShaderOutput( auto Type = FVulkanShaderSerializedBindings::TYPE_MAX; switch (CurrBinding.Type) { - case FVulkanBindingTable::TYPE_SAMPLER: - Type = FVulkanShaderSerializedBindings::TYPE_SAMPLER; + //case FVulkanBindingTable::TYPE_SAMPLER: + // Type = FVulkanShaderSerializedBindings::TYPE_SAMPLER; + // break; + case FVulkanBindingTable::TYPE_COMBINED_IMAGE_SAMPLER: + Type = FVulkanShaderSerializedBindings::TYPE_COMBINED_IMAGE_SAMPLER; break; case FVulkanBindingTable::TYPE_SAMPLER_BUFFER: Type = FVulkanShaderSerializedBindings::TYPE_SAMPLER_BUFFER; @@ -909,7 +912,7 @@ FCompilerInfo::FCompilerInfo(const FShaderCompilerInput& InInput, const FString& /** * Compile a shader using the external shader compiler - */ + * static void CompileUsingExternal(const struct FShaderCompilerInput& Input, struct FShaderCompilerOutput& Output, const class FString& WorkingDirectory, EVulkanShaderVersion Version) { FString PreprocessedShader; @@ -1033,7 +1036,7 @@ static void CompileUsingExternal(const struct FShaderCompilerInput& Input, struc FVulkanBindingTable BindingTableES(Frequency); FVulkanCodeBackend VulkanBackendES(CCFlagsES, BindingTableES, HlslCompilerTargetES); - FVulkanLanguageSpec VulkanLanguageSpec(false); + FVulkanLanguageSpec VulkanLanguageSpec(false, true); int32 Result = 0; if (!bIsSM5) @@ -1271,8 +1274,8 @@ static bool CallHlslcc(const FString& PreprocessedShader, FVulkanBindingTable& B // Call hlslcc FVulkanCodeBackend VulkanBackend(CompilerInfo.CCFlags, BindingTable, HlslCompilerTarget); FHlslCrossCompilerContext CrossCompilerContext(CompilerInfo.CCFlags, CompilerInfo.Frequency, HlslCompilerTarget); - //#todo-rco: Always false? - FVulkanLanguageSpec VulkanLanguageSpec(false); + const bool bShareSamplers = false; + FVulkanLanguageSpec VulkanLanguageSpec(bShareSamplers); int32 Result = 0; if (CrossCompilerContext.Init(TCHAR_TO_ANSI(*CompilerInfo.Input.SourceFilename), &VulkanLanguageSpec)) { @@ -1343,12 +1346,12 @@ void CompileShader_Windows_Vulkan(const FShaderCompilerInput& Input, FShaderComp { check(IsVulkanPlatform((EShaderPlatform)Input.Target.Platform)); - if (GUseExternalShaderCompiler) - { - // Old path... - CompileUsingExternal(Input, Output, WorkingDirectory, Version); - return; - } + //if (GUseExternalShaderCompiler) + //{ + // // Old path... + // CompileUsingExternal(Input, Output, WorkingDirectory, Version); + // return; + //} const bool bIsSM5 = (Version == EVulkanShaderVersion::SM5); const bool bIsSM4 = (Version == EVulkanShaderVersion::SM4); @@ -1505,8 +1508,9 @@ void CompileShader_Windows_Vulkan(const FShaderCompilerInput& Input, FShaderComp //} //else { - // For debugging... - auto* Code = GeneratedGlslSource.GetData(); + // For debugging; if you hit an error from Glslang/Spirv, use the SourceNoHeader for line numbers + auto* SourceWithHeader = GeneratedGlslSource.GetData(); + char* SourceNoHeader = strstr(SourceWithHeader, "#version"); CompileUsingInternal(CompilerInfo, BindingTable, GeneratedGlslSource, EntryPointName, Output); } } diff --git a/Engine/Source/Editor/MaterialEditor/Private/SMaterialEditorViewport.cpp b/Engine/Source/Editor/MaterialEditor/Private/SMaterialEditorViewport.cpp index 44cd41aeab10..17d670d11ceb 100644 --- a/Engine/Source/Editor/MaterialEditor/Private/SMaterialEditorViewport.cpp +++ b/Engine/Source/Editor/MaterialEditor/Private/SMaterialEditorViewport.cpp @@ -124,7 +124,7 @@ FLinearColor FMaterialEditorViewportClient::GetBackgroundColor() const { BackgroundColor = FLinearColor::White; } - else if(PreviewBlendMode == BLEND_Translucent) + else if(PreviewBlendMode == BLEND_Translucent || PreviewBlendMode == BLEND_AlphaComposite) { BackgroundColor = FColor(64, 64, 64); } diff --git a/Engine/Source/Editor/NiagaraEditor/NiagaraEditor.Build.cs b/Engine/Source/Editor/NiagaraEditor/NiagaraEditor.Build.cs index b38485e96a58..32332daff51f 100644 --- a/Engine/Source/Editor/NiagaraEditor/NiagaraEditor.Build.cs +++ b/Engine/Source/Editor/NiagaraEditor/NiagaraEditor.Build.cs @@ -8,8 +8,9 @@ public class NiagaraEditor : ModuleRules { PrivateDependencyModuleNames.AddRange( new string[] { - "Engine", - "Core", + "Engine", + "RHI", + "Core", "CoreUObject", "InputCore", "RenderCore", diff --git a/Engine/Source/Editor/NiagaraEditor/Private/NiagaraCompiler.cpp b/Engine/Source/Editor/NiagaraEditor/Private/NiagaraCompiler.cpp index bfd916c7de0c..745f54284f89 100644 --- a/Engine/Source/Editor/NiagaraEditor/Private/NiagaraCompiler.cpp +++ b/Engine/Source/Editor/NiagaraEditor/Private/NiagaraCompiler.cpp @@ -172,8 +172,16 @@ bool FNiagaraCompiler::CheckOutputs(FName OpName, TArray& Outpu void FNiagaraCompiler::Error(FText ErrorText, UNiagaraNode* Node, UEdGraphPin* Pin) { - FString ErrorString = FString::Printf(TEXT("Node: @@ - Pin: @@ - %s"), *ErrorText.ToString()); - MessageLog.Error(*ErrorString, Node, Pin); + if (Pin) + { + FString ErrorString = FString::Printf(TEXT("Node: @@ - Pin: @@ - %s"), *ErrorText.ToString()); + MessageLog.Error(*ErrorString, Node, Pin); + } + else + { + FString ErrorString = FString::Printf(TEXT("Node: @@ - %s"), *ErrorText.ToString()); + MessageLog.Error(*ErrorString, Node); + } } void FNiagaraCompiler::Warning(FText WarningText, UNiagaraNode* Node, UEdGraphPin* Pin) diff --git a/Engine/Source/Editor/NiagaraEditor/Private/NiagaraEmitterPropertiesDetailsCustomization.cpp b/Engine/Source/Editor/NiagaraEditor/Private/NiagaraEmitterPropertiesDetailsCustomization.cpp index 5bd14f5bd3fc..245cab41e089 100644 --- a/Engine/Source/Editor/NiagaraEditor/Private/NiagaraEmitterPropertiesDetailsCustomization.cpp +++ b/Engine/Source/Editor/NiagaraEditor/Private/NiagaraEmitterPropertiesDetailsCustomization.cpp @@ -91,8 +91,8 @@ void FNiagaraEmitterPropertiesDetails::BuildScriptProperties(TSharedRef ElementProperty, int32 ElementIndex, IDetailChildrenBuilder& ChildrenBuilder) { - TSharedPtr ValueProperty = ElementProperty->GetChildHandle(GET_MEMBER_NAME_CHECKED(FNiagaraConstants_Float, Value)); - TSharedPtr NameProperty = ElementProperty->GetChildHandle(GET_MEMBER_NAME_CHECKED(FNiagaraConstants_Float, Name)); + TSharedPtr ValueProperty = ElementProperty->GetChildHandle(GET_MEMBER_NAME_CHECKED(FNiagaraConstant_Float, Value)); + TSharedPtr NameProperty = ElementProperty->GetChildHandle(GET_MEMBER_NAME_CHECKED(FNiagaraConstant_Float, Name)); FName DisplayName; NameProperty->GetValue(DisplayName); @@ -105,8 +105,8 @@ void FNiagaraEmitterPropertiesDetails::OnGenerateScalarConstantEntry(TSharedRef< void FNiagaraEmitterPropertiesDetails::OnGenerateVectorConstantEntry(TSharedRef ElementProperty, int32 ElementIndex, IDetailChildrenBuilder& ChildrenBuilder) { - TSharedPtr ValueProperty = ElementProperty->GetChildHandle(GET_MEMBER_NAME_CHECKED(FNiagaraConstants_Vector, Value)); - TSharedPtr NameProperty = ElementProperty->GetChildHandle(GET_MEMBER_NAME_CHECKED(FNiagaraConstants_Vector, Name)); + TSharedPtr ValueProperty = ElementProperty->GetChildHandle(GET_MEMBER_NAME_CHECKED(FNiagaraConstant_Vector, Value)); + TSharedPtr NameProperty = ElementProperty->GetChildHandle(GET_MEMBER_NAME_CHECKED(FNiagaraConstant_Vector, Name)); FName DisplayName; NameProperty->GetValue(DisplayName); @@ -119,8 +119,8 @@ void FNiagaraEmitterPropertiesDetails::OnGenerateVectorConstantEntry(TSharedRef< void FNiagaraEmitterPropertiesDetails::OnGenerateMatrixConstantEntry(TSharedRef ElementProperty, int32 ElementIndex, IDetailChildrenBuilder& ChildrenBuilder) { - TSharedPtr ValueProperty = ElementProperty->GetChildHandle(GET_MEMBER_NAME_CHECKED(FNiagaraConstants_Matrix, Value)); - TSharedPtr NameProperty = ElementProperty->GetChildHandle(GET_MEMBER_NAME_CHECKED(FNiagaraConstants_Matrix, Name)); + TSharedPtr ValueProperty = ElementProperty->GetChildHandle(GET_MEMBER_NAME_CHECKED(FNiagaraConstant_Matrix, Value)); + TSharedPtr NameProperty = ElementProperty->GetChildHandle(GET_MEMBER_NAME_CHECKED(FNiagaraConstant_Matrix, Name)); FName DisplayName; NameProperty->GetValue(DisplayName); diff --git a/Engine/Source/Editor/NiagaraEditor/Private/NiagaraNodeConstant.cpp b/Engine/Source/Editor/NiagaraEditor/Private/NiagaraNodeConstant.cpp deleted file mode 100644 index 423eccfabb00..000000000000 --- a/Engine/Source/Editor/NiagaraEditor/Private/NiagaraNodeConstant.cpp +++ /dev/null @@ -1,4 +0,0 @@ -// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. - -#include "NiagaraEditorPrivatePCH.h" -#include "INiagaraCompiler.h" diff --git a/Engine/Source/Editor/NiagaraEditor/Private/NiagaraNodeGetAttr.cpp b/Engine/Source/Editor/NiagaraEditor/Private/NiagaraNodeGetAttr.cpp deleted file mode 100644 index 423eccfabb00..000000000000 --- a/Engine/Source/Editor/NiagaraEditor/Private/NiagaraNodeGetAttr.cpp +++ /dev/null @@ -1,4 +0,0 @@ -// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. - -#include "NiagaraEditorPrivatePCH.h" -#include "INiagaraCompiler.h" diff --git a/Engine/Source/Editor/NiagaraEditor/Private/NiagaraNodeOutputUpdate.cpp b/Engine/Source/Editor/NiagaraEditor/Private/NiagaraNodeOutputUpdate.cpp deleted file mode 100644 index c3cad89c7c34..000000000000 --- a/Engine/Source/Editor/NiagaraEditor/Private/NiagaraNodeOutputUpdate.cpp +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. - -#include "NiagaraEditorPrivatePCH.h" -#include "BlueprintGraphDefinitions.h" -#include "GraphEditorSettings.h" - diff --git a/Engine/Source/Editor/NiagaraEditor/Private/NiagaraScriptSource.cpp b/Engine/Source/Editor/NiagaraEditor/Private/NiagaraScriptSource.cpp index 07643d692968..544de38c6c61 100644 --- a/Engine/Source/Editor/NiagaraEditor/Private/NiagaraScriptSource.cpp +++ b/Engine/Source/Editor/NiagaraEditor/Private/NiagaraScriptSource.cpp @@ -228,7 +228,7 @@ void UNiagaraScriptSource::GetEmitterAttributes(TArray& VectorInputs, TAr { for (uint32 i=0; i < NiagaraConstants::NumBuiltinConstants; i++) { - VectorInputs.Add(NiagaraConstants::ConstantNames[i]); + VectorInputs.Add(NiagaraConstants::GConstantNames[i]); } MatrixInputs.Empty(); diff --git a/Engine/Source/Editor/NiagaraEditor/Private/SNiagaraEffectEditorWidget.cpp b/Engine/Source/Editor/NiagaraEditor/Private/SNiagaraEffectEditorWidget.cpp index 70d24c27b5db..ddc17d7b0340 100644 --- a/Engine/Source/Editor/NiagaraEditor/Private/SNiagaraEffectEditorWidget.cpp +++ b/Engine/Source/Editor/NiagaraEditor/Private/SNiagaraEffectEditorWidget.cpp @@ -676,8 +676,9 @@ void SEmitterWidget::OnRenderModuleChanged(TSharedPtr ModName, ESelectI UMaterial *Material = UMaterial::GetDefaultMaterial(MD_Surface); Emitter->GetEffectRenderer()->SetMaterial(Material, EffectInstance->GetComponent()->GetWorld()->FeatureLevel); - - TComponentReregisterContext ComponentReregisterContext; + { + TComponentReregisterContext ComponentReregisterContext; + } UObject *Props = Emitter->GetProperties()->RendererProperties; RendererPropertiesView->SetObject(Props); } diff --git a/Engine/Source/Editor/NiagaraEditor/Public/NiagaraNodeConstant.h b/Engine/Source/Editor/NiagaraEditor/Public/NiagaraNodeConstant.h deleted file mode 100644 index e632c6059618..000000000000 --- a/Engine/Source/Editor/NiagaraEditor/Public/NiagaraNodeConstant.h +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. - -#pragma once - -#include "NiagaraCommon.h" -#include "NiagaraNodeConstant.generated.h" diff --git a/Engine/Source/Editor/NiagaraEditor/Public/NiagaraNodeGetAttr.h b/Engine/Source/Editor/NiagaraEditor/Public/NiagaraNodeGetAttr.h deleted file mode 100644 index 4dea2dbd06aa..000000000000 --- a/Engine/Source/Editor/NiagaraEditor/Public/NiagaraNodeGetAttr.h +++ /dev/null @@ -1,4 +0,0 @@ -// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. - -#pragma once -#include "NiagaraNodeGetAttr.generated.h" diff --git a/Engine/Source/Editor/NiagaraEditor/Public/NiagaraNodeOutputUpdate.h b/Engine/Source/Editor/NiagaraEditor/Public/NiagaraNodeOutputUpdate.h deleted file mode 100644 index 9c90efd52573..000000000000 --- a/Engine/Source/Editor/NiagaraEditor/Public/NiagaraNodeOutputUpdate.h +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. - -#pragma once -#include "NiagaraNode.h" -#include "NiagaraNodeOutputUpdate.generated.h" - diff --git a/Engine/Source/Editor/UnrealEd/Private/EditorBuildUtils.cpp b/Engine/Source/Editor/UnrealEd/Private/EditorBuildUtils.cpp index ffb2cf44cd04..849f12310a16 100644 --- a/Engine/Source/Editor/UnrealEd/Private/EditorBuildUtils.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/EditorBuildUtils.cpp @@ -1068,6 +1068,9 @@ bool FEditorBuildUtils::EditorBuildTextureStreaming(UWorld* InWorld, bool bWithT FScopedSlowTask SlowTask((float)TexCoordScales.Num(), (LOCTEXT("TextureStreamingBuild_ExportingMaterialScales", "Exporting Material TexCoord Scales"))); const double StartTime = FPlatformTime::Seconds(); + + FMaterialUtilities::FExportErrorManager ExportErrors(FeatureLevel); + for (FTexCoordScaleMap::TIterator It(TexCoordScales); It; ++It) { SlowTask.EnterProgressFrame(); @@ -1078,9 +1081,11 @@ bool FEditorBuildUtils::EditorBuildTextureStreaming(UWorld* InWorld, bool bWithT TArray& Scales = It.Value(); - FMaterialUtilities::ExportMaterialTexCoordScales(MaterialInterface, QualityLevel, FeatureLevel, Scales); + FMaterialUtilities::ExportMaterialTexCoordScales(MaterialInterface, QualityLevel, FeatureLevel, Scales, ExportErrors); } UE_LOG(LogLevel, Display, TEXT("Export Material TexCoord Scales took %.3f seconds."), FPlatformTime::Seconds() - StartTime); + + ExportErrors.OutputToLog(); } if (bDebugDataOnly) diff --git a/Engine/Source/Editor/UnrealEd/Private/Lightmass/LightmassRender.cpp b/Engine/Source/Editor/UnrealEd/Private/Lightmass/LightmassRender.cpp index 14e2afe5e33c..c1be4ec28ccb 100644 --- a/Engine/Source/Editor/UnrealEd/Private/Lightmass/LightmassRender.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/Lightmass/LightmassRender.cpp @@ -376,7 +376,7 @@ public: return Compiler->Saturate(Compiler->ForceCast(MaterialInterface->CompileProperty(Compiler, DiffuseInput),MCT_Float3,true,true)); } } - else if ((BlendMode == BLEND_Translucent) || (BlendMode == BLEND_Additive)) + else if ((BlendMode == BLEND_Translucent) || (BlendMode == BLEND_Additive || (BlendMode == BLEND_AlphaComposite))) { int32 ColoredOpacity = -1; if (ShadingModel == MSM_Unlit) @@ -599,7 +599,8 @@ public: else if ((BlendMode == BLEND_Modulate) || (BlendMode == BLEND_Translucent) || - (BlendMode == BLEND_Additive)) + (BlendMode == BLEND_Additive) || + (BlendMode == BLEND_AlphaComposite)) { bool bColorInputIsNULL = false; if (ShadingModel == MSM_Unlit) @@ -611,7 +612,8 @@ public: bColorInputIsNULL = !IsMaterialInputConnected(Material, MP_DiffuseColor); } if (BlendMode == BLEND_Translucent - || BlendMode == BLEND_Additive) + || BlendMode == BLEND_Additive + || BlendMode == BLEND_AlphaComposite) { bExpressionIsNULL = bColorInputIsNULL && !IsMaterialInputConnected(Material, PropertyToCompile); } @@ -721,6 +723,7 @@ public: break; case BLEND_Translucent: case BLEND_Additive: + case BLEND_AlphaComposite: { switch (InMaterialProperty) { diff --git a/Engine/Source/Editor/UnrealEd/Private/MaterialGraphNode.cpp b/Engine/Source/Editor/UnrealEd/Private/MaterialGraphNode.cpp index ab4c6b564499..719525768b17 100644 --- a/Engine/Source/Editor/UnrealEd/Private/MaterialGraphNode.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/MaterialGraphNode.cpp @@ -457,15 +457,15 @@ void UMaterialGraphNode::CreateInputPins() } else if ( !FCString::Stricmp( *InputName, TEXT("AGreaterThanB") ) ) { - InputName = TEXT("A>=B"); + InputName = TEXT("A > B"); } else if ( !FCString::Stricmp( *InputName, TEXT("AEqualsB") ) ) { - InputName = TEXT("A==B"); + InputName = TEXT("A == B"); } else if ( !FCString::Stricmp( *InputName, TEXT("ALessThanB") ) ) { - InputName = TEXT("AGetWorld(); if( World && SceneCapturesToUpdateMap.Num() > 0 ) { - // We must push any deferred render state recreations before causing any rendering to happen, to make sure that deleted resource references are updated - World->SendAllEndOfFrameUpdates(); - // Only update the scene captures assoicated with the current scene. + // Only update the scene captures associated with the current scene. // Updating others not associated with the scene would cause invalid data to be rendered into the target TArray< TWeakObjectPtr > SceneCapturesToUpdate; SceneCapturesToUpdateMap.MultiFind( World, SceneCapturesToUpdate ); @@ -736,8 +734,6 @@ void USceneCaptureComponentCube::UpdateDeferredCaptures( FSceneInterface* Scene if( World && CubedSceneCapturesToUpdateMap.Num() > 0 ) { - // We must push any deferred render state recreations before causing any rendering to happen, to make sure that deleted resource references are updated - World->SendAllEndOfFrameUpdates(); // Only update the scene captures associated with the current scene. // Updating others not associated with the scene would cause invalid data to be rendered into the target TArray< TWeakObjectPtr > SceneCapturesToUpdate; diff --git a/Engine/Source/Runtime/Engine/Private/DestructibleMesh.cpp b/Engine/Source/Runtime/Engine/Private/DestructibleMesh.cpp index 0a9fe54a80ea..970f1e6f7717 100644 --- a/Engine/Source/Runtime/Engine/Private/DestructibleMesh.cpp +++ b/Engine/Source/Runtime/Engine/Private/DestructibleMesh.cpp @@ -11,6 +11,7 @@ #include "Engine/DestructibleFractureSettings.h" #include "PhysicsEngine/PhysXSupport.h" #include "EditorFramework/AssetImportData.h" +#include "GPUSkinVertexFactory.h" #if WITH_APEX && WITH_EDITOR #include "ApexDestructibleAssetImport.h" @@ -39,8 +40,8 @@ void UDestructibleMesh::PostLoad() // you'll have to save re-chunked asset here, but I don't have a good way to let user // know here since PostLoad invalidate any dirty package mark. FSkeletalMeshResource* ImportedMeshResource = GetImportedResource(); - static IConsoleVariable* MaxBonesVar = IConsoleManager::Get().FindConsoleVariable(TEXT("Compat.MAX_GPUSKIN_BONES")); - const int32 MaxGPUSkinBones = MaxBonesVar->GetInt(); + const uint32 MaxGPUSkinBones = FGPUBaseSkinVertexFactory::GetMaxGPUSkinBones(); + check(MaxGPUSkinBones <= FGPUBaseSkinVertexFactory::GHardwareMaxGPUSkinBones); // if this doesn't have the right MAX GPU Bone count, recreate it. for(int32 LodIndex=0; LodIndex MaxGPUSkinBones) + if (ThisLODModel.Sections[SectionIndex].BoneMap.Num() > (int)MaxGPUSkinBones) { #if WITH_EDITOR // re create destructible asset if it exceeds diff --git a/Engine/Source/Runtime/Engine/Private/LevelTick.cpp b/Engine/Source/Runtime/Engine/Private/LevelTick.cpp index 5578224f8b5e..4366ae1cd346 100644 --- a/Engine/Source/Runtime/Engine/Private/LevelTick.cpp +++ b/Engine/Source/Runtime/Engine/Private/LevelTick.cpp @@ -1369,9 +1369,6 @@ void UWorld::Tick( ELevelTick TickType, float DeltaSeconds ) { // Update SpeedTree wind objects. Scene->UpdateSpeedTreeWind(TimeSeconds); - - USceneCaptureComponent2D::UpdateDeferredCaptures( Scene ); - USceneCaptureComponentCube::UpdateDeferredCaptures( Scene ); } // Tick the FX system. diff --git a/Engine/Source/Runtime/Engine/Private/Materials/MaterialExpressions.cpp b/Engine/Source/Runtime/Engine/Private/Materials/MaterialExpressions.cpp index 49b8f3d2cbe4..e2f2748e3467 100644 --- a/Engine/Source/Runtime/Engine/Private/Materials/MaterialExpressions.cpp +++ b/Engine/Source/Runtime/Engine/Private/Materials/MaterialExpressions.cpp @@ -8807,7 +8807,7 @@ UMaterialExpressionNoise::UMaterialExpressionNoise(const FObjectInitializer& Obj Scale = 1.0f; Levels = 6; - Quality = 0; + Quality = 1; OutputMin = -1.0f; OutputMax = 1.0f; LevelScale = 2.0f; @@ -8829,7 +8829,9 @@ bool UMaterialExpressionNoise::CanEditChange(const UProperty* InProperty) const FName PropertyFName = InProperty->GetFName(); bool bTilableNoiseType = NoiseFunction == NOISEFUNCTION_GradientALU || NoiseFunction == NOISEFUNCTION_ValueALU - || NoiseFunction == NOISEFUNCTION_GradientTex; + || NoiseFunction == NOISEFUNCTION_GradientTex || NoiseFunction == NOISEFUNCTION_VoronoiALU; + + bool bSupportsQuality = (NoiseFunction == NOISEFUNCTION_VoronoiALU); if (PropertyFName == GET_MEMBER_NAME_CHECKED(UMaterialExpressionNoise, bTiling)) { @@ -8839,6 +8841,11 @@ bool UMaterialExpressionNoise::CanEditChange(const UProperty* InProperty) const { bIsEditable = bTilableNoiseType && bTiling; } + + if (PropertyFName == GET_MEMBER_NAME_CHECKED(UMaterialExpressionNoise, Quality)) + { + bIsEditable = bSupportsQuality; + } } return bIsEditable; diff --git a/Engine/Source/Runtime/Engine/Private/Materials/MaterialShader.cpp b/Engine/Source/Runtime/Engine/Private/Materials/MaterialShader.cpp index 9059748117b8..3579ea0331d3 100644 --- a/Engine/Source/Runtime/Engine/Private/Materials/MaterialShader.cpp +++ b/Engine/Source/Runtime/Engine/Private/Materials/MaterialShader.cpp @@ -86,6 +86,7 @@ FString GetBlendModeString(EBlendMode BlendMode) case BLEND_Translucent: BlendModeName = TEXT("BLEND_Translucent"); break; case BLEND_Additive: BlendModeName = TEXT("BLEND_Additive"); break; case BLEND_Modulate: BlendModeName = TEXT("BLEND_Modulate"); break; + case BLEND_AlphaComposite: BlendModeName = TEXT("BLEND_AlphaComposite"); break; default: BlendModeName = TEXT("Unknown"); break; } return BlendModeName; diff --git a/Engine/Source/Runtime/Engine/Private/Materials/MaterialShared.cpp b/Engine/Source/Runtime/Engine/Private/Materials/MaterialShared.cpp index dcefe67da4de..5ec00e366980 100644 --- a/Engine/Source/Runtime/Engine/Private/Materials/MaterialShared.cpp +++ b/Engine/Source/Runtime/Engine/Private/Materials/MaterialShared.cpp @@ -1377,6 +1377,11 @@ void FMaterial::SetupMaterialEnvironment( } break; } + case BLEND_AlphaComposite: + { + // Fall through the case, blend mode will reuse MATERIALBLENDING_TRANSLUCENT + OutEnvironment.SetDefine(TEXT("MATERIALBLENDING_ALPHACOMPOSITE"), TEXT("1")); + } case BLEND_Translucent: OutEnvironment.SetDefine(TEXT("MATERIALBLENDING_TRANSLUCENT"),TEXT("1")); break; case BLEND_Additive: OutEnvironment.SetDefine(TEXT("MATERIALBLENDING_ADDITIVE"),TEXT("1")); break; case BLEND_Modulate: OutEnvironment.SetDefine(TEXT("MATERIALBLENDING_MODULATE"),TEXT("1")); break; diff --git a/Engine/Source/Runtime/Engine/Private/Particles/ParticleBeamModules.cpp b/Engine/Source/Runtime/Engine/Private/Particles/ParticleBeamModules.cpp index 9ba7956809b6..47b7d9a500aa 100644 --- a/Engine/Source/Runtime/Engine/Private/Particles/ParticleBeamModules.cpp +++ b/Engine/Source/Runtime/Engine/Private/Particles/ParticleBeamModules.cpp @@ -1575,6 +1575,13 @@ void UParticleModuleBeamNoise::PostEditChangeProperty(FPropertyChangedEvent& Pro UProperty* PropertyThatChanged = PropertyChangedEvent.Property; if (PartSys && PropertyThatChanged) { + // Make sure that the interpolation count is > 0. + if (PropertyThatChanged->GetFName() == FName(TEXT("NoiseTessellation"))) + { + // Clamp the tessellation + NoiseTessellation = FMath::Clamp(NoiseTessellation, 0, UParticleModuleBeamNoise::MaxNoiseTessellation); + } + PartSys->PostEditChangeProperty(PropertyChangedEvent); } diff --git a/Engine/Source/Runtime/Engine/Private/Particles/ParticleGpuSimulation.cpp b/Engine/Source/Runtime/Engine/Private/Particles/ParticleGpuSimulation.cpp index 2f301802dafc..15f647dc48c8 100644 --- a/Engine/Source/Runtime/Engine/Private/Particles/ParticleGpuSimulation.cpp +++ b/Engine/Source/Runtime/Engine/Private/Particles/ParticleGpuSimulation.cpp @@ -33,6 +33,7 @@ #include "GlobalDistanceFieldParameters.h" DECLARE_CYCLE_STAT(TEXT("GPUSpriteEmitterInstance Init"), STAT_GPUSpriteEmitterInstance_Init, STATGROUP_Particles); +DECLARE_FLOAT_COUNTER_STAT(TEXT("Particle Simulation"), Stat_GPU_ParticleSimulation, STATGROUP_GPU); /*------------------------------------------------------------------------------ Constants to tune memory and performance for GPU particle simulation. @@ -1390,6 +1391,8 @@ void ExecuteSimulationCommands( } SCOPED_DRAW_EVENT(RHICmdList, ParticleSimulation); + SCOPED_GPU_STAT(RHICmdList, Stat_GPU_ParticleSimulation); + const float FixDeltaSeconds = CVarGPUParticleFixDeltaSeconds.GetValueOnRenderThread(); const FParticleStateTextures& TextureResources = (FixDeltaSeconds <= 0 || bUseFixDT) ? ParticleSimulationResources->GetPreviousStateTextures() : ParticleSimulationResources->GetCurrentStateTextures(); @@ -1500,6 +1503,7 @@ void ClearTiles(FRHICommandList& RHICmdList, ERHIFeatureLevel::Type FeatureLevel } SCOPED_DRAW_EVENT(RHICmdList, ClearTiles); + SCOPED_GPU_STAT(RHICmdList, Stat_GPU_ParticleSimulation); const int32 MaxTilesPerDrawCallUnaligned = GParticleScratchVertexBufferSize / sizeof(FVector2D); const int32 MaxTilesPerDrawCall = MaxTilesPerDrawCallUnaligned & (~(TILES_PER_INSTANCE-1)); @@ -4657,6 +4661,7 @@ void FFXSystem::SimulateGPUParticles( if (NewParticles.Num()) { SCOPED_DRAW_EVENT(RHICmdList, ParticleInjection); + SCOPED_GPU_STAT(RHICmdList, Stat_GPU_ParticleSimulation); FParticleStateTextures& CurrentStateTextures = ParticleSimulationResources->GetCurrentStateTextures(); diff --git a/Engine/Source/Runtime/Engine/Private/Particles/ParticleSystemRender.cpp b/Engine/Source/Runtime/Engine/Private/Particles/ParticleSystemRender.cpp index ccd823097d37..d81a1ddb34b9 100644 --- a/Engine/Source/Runtime/Engine/Private/Particles/ParticleSystemRender.cpp +++ b/Engine/Source/Runtime/Engine/Private/Particles/ParticleSystemRender.cpp @@ -500,7 +500,6 @@ void FDynamicSpriteEmitterDataBase::BuildViewFillData( int32 NumIndices, IndexStride; GetIndexAllocInfo(NumIndices, IndexStride); - check((uint32)NumIndices <= 65535); check(IndexStride > 0); DynamicIndexAllocation = FGlobalDynamicIndexBuffer::Get().Allocate( NumIndices, IndexStride ); @@ -1060,7 +1059,7 @@ void FDynamicSpriteEmitterData::GetDynamicMeshElementsEmitter(const FParticleSys const FMaterial* Material = MaterialResource[bSelected]->GetMaterial(FeatureLevel); if (Material && - (Material->GetBlendMode() == BLEND_Translucent || + (Material->GetBlendMode() == BLEND_Translucent || Material->GetBlendMode() == BLEND_AlphaComposite || ((SourceData->SortMode == PSORTMODE_Age_OldestFirst) || (SourceData->SortMode == PSORTMODE_Age_NewestFirst))) ) { @@ -3194,6 +3193,11 @@ static int32 CreateDynamicBeam2EmitterIndices(TIndexType* OutIndex, const FDynam TIndexType VertexIndex = 0; TIndexType StartVertexIndex = 0; + TIndexType *BaseIndex = OutIndex; + + // Signed as we are comparing against pointer arithmetic + const int32 MaxIndexCount = 65535; + for (int32 Beam = 0; Beam < Source.ActiveParticleCount; Beam++) { DECLARE_PARTICLE_PTR(Particle, Source.DataContainer.ParticleData + Source.ParticleStride * Beam); @@ -3209,17 +3213,22 @@ static int32 CreateDynamicBeam2EmitterIndices(TIndexType* OutIndex, const FDynam if (VertexIndex == 0)//First Beam { - *(OutIndex++) = VertexIndex++; // SheetIndex + 0 - *(OutIndex++) = VertexIndex++; // SheetIndex + 1 + if ((OutIndex - BaseIndex <= MaxIndexCount - 2)) + { + *(OutIndex++) = VertexIndex++; // SheetIndex + 0 + *(OutIndex++) = VertexIndex++; // SheetIndex + 1 + } } else//Degenerate tris between beams { - *(OutIndex++) = VertexIndex - 1; // Last vertex of the previous sheet - *(OutIndex++) = VertexIndex; // First vertex of the next sheet - *(OutIndex++) = VertexIndex++; // First vertex of the next sheet - *(OutIndex++) = VertexIndex++; // Second vertex of the next sheet - - TrianglesToRender += 4; + if ((OutIndex - BaseIndex <= MaxIndexCount - 4)) + { + *(OutIndex++) = VertexIndex - 1; // Last vertex of the previous sheet + *(OutIndex++) = VertexIndex; // First vertex of the next sheet + *(OutIndex++) = VertexIndex++; // First vertex of the next sheet + *(OutIndex++) = VertexIndex++; // Second vertex of the next sheet + TrianglesToRender += 4; + } } for (int32 SheetIndex = 0; SheetIndex < Source.Sheets; SheetIndex++) @@ -3231,10 +3240,16 @@ static int32 CreateDynamicBeam2EmitterIndices(TIndexType* OutIndex, const FDynam for (int32 i = 0; i < BeamPayloadData->TriangleCount; i++) { *(OutIndex++) = VertexIndex++; + + if (OutIndex - BaseIndex > MaxIndexCount) + { + break; + } } // Degenerate tris - if ((SheetIndex + 1) < Source.Sheets) + if ((SheetIndex + 1) < Source.Sheets + && (OutIndex - BaseIndex <= MaxIndexCount-4)) { *(OutIndex++) = VertexIndex - 1; // Last vertex of the previous sheet *(OutIndex++) = VertexIndex; // First vertex of the next sheet @@ -3243,6 +3258,12 @@ static int32 CreateDynamicBeam2EmitterIndices(TIndexType* OutIndex, const FDynam TrianglesToRender += 4; } + + if (OutIndex - BaseIndex > MaxIndexCount) + { + break; + } + } } diff --git a/Engine/Source/Runtime/Engine/Private/Particles/ParticleTrail2EmitterInstance.cpp b/Engine/Source/Runtime/Engine/Private/Particles/ParticleTrail2EmitterInstance.cpp index e533f18435a1..4e6c79e8361c 100644 --- a/Engine/Source/Runtime/Engine/Private/Particles/ParticleTrail2EmitterInstance.cpp +++ b/Engine/Source/Runtime/Engine/Private/Particles/ParticleTrail2EmitterInstance.cpp @@ -2185,7 +2185,7 @@ bool FParticleRibbonEmitterInstance::ResolveSourcePoint(int32 InTrailIdx, ResolveSource(); } - if (SourceEmitter && SourceEmitter->ParticleIndices) + if (SourceEmitter && SourceEmitter->ParticleIndices && SourceEmitter->ActiveParticles > 0) { if (SourceIndices[InTrailIdx] != -1) { @@ -2227,6 +2227,7 @@ bool FParticleRibbonEmitterInstance::ResolveSourcePoint(int32 InTrailIdx, if (SourceIndices[TrailCheckIdx] == SourceEmitter->ParticleIndices[Index]) { Index = -1; + break; } } } diff --git a/Engine/Source/Runtime/Engine/Private/PointLightSceneProxy.h b/Engine/Source/Runtime/Engine/Private/PointLightSceneProxy.h index 2602a1134731..1432fa2db39a 100644 --- a/Engine/Source/Runtime/Engine/Private/PointLightSceneProxy.h +++ b/Engine/Source/Runtime/Engine/Private/PointLightSceneProxy.h @@ -39,6 +39,8 @@ public: , SourceRadius(Component->SourceRadius) , SourceLength(Component->SourceLength) , bInverseSquared(Component->bUseInverseSquaredFalloff) + , MaxDrawDistance(Component->MaxDrawDistance) + , FadeRange(Component->MaxDistanceFadeRange) { UpdateRadius(Component->AttenuationRadius); } @@ -50,6 +52,15 @@ public: void UpdateRadius_GameThread(UPointLightComponent* Component); // FLightSceneInfo interface. + virtual float GetMaxDrawDistance() const final override + { + return MaxDrawDistance; + } + + virtual float GetFadeRange() const final override + { + return FadeRange; + } /** @return radius of the light or 0 if no radius */ virtual float GetRadius() const override @@ -147,6 +158,9 @@ private: // Min to avoid div by 0 (NaN in InvRadius) InvRadius = 1.0f / FMath::Max(0.00001f, ComponentRadius); } + + float MaxDrawDistance; + float FadeRange; }; /** diff --git a/Engine/Source/Runtime/Engine/Private/SceneUtils.cpp b/Engine/Source/Runtime/Engine/Private/SceneUtils.cpp index 01ef9295eda4..af74e66d33e6 100644 --- a/Engine/Source/Runtime/Engine/Private/SceneUtils.cpp +++ b/Engine/Source/Runtime/Engine/Private/SceneUtils.cpp @@ -4,6 +4,24 @@ #include "RHI.h" #include "SceneUtils.h" + +#if HAS_GPU_STATS + +static TAutoConsoleVariable CVarGPUStatsEnabled( + TEXT("r.GPUStatsEnabled"), + 0, + TEXT("Enables or disables GPU stat recording")); + +// If this is enabled, the child stat timings will be included in their parents' times. +// This presents problems for non-hierarchical stats if we're expecting them to add up +// to the total GPU time, so we probably want this disabled +#define GPU_STATS_CHILD_TIMES_INCLUDED 0 + +DECLARE_FLOAT_COUNTER_STAT(TEXT("[TOTAL SCENE]"), Stat_GPU_Total, STATGROUP_GPU); + +#endif //HAS_GPU_STATS + + #if WANTS_DRAW_MESH_EVENTS template @@ -83,3 +101,365 @@ bool IsMobileHDRMosaic() return !(GSupportsHDR32bppEncodeModeIntrinsic && GSupportsShaderFramebufferFetch); } } + +#if HAS_GPU_STATS +static const int32 NumGPUProfilerBufferedFrames = 4; + +/*----------------------------------------------------------------------------- +FRealTimeGPUProfilerEvent class +-----------------------------------------------------------------------------*/ +class FRealtimeGPUProfilerEvent +{ +public: + static const uint64 InvalidQueryResult = 0xFFFFFFFFFFFFFFFFull; + +public: + FRealtimeGPUProfilerEvent(const TStatId& InStatId) + : StartResultMicroseconds(InvalidQueryResult) + , EndResultMicroseconds(InvalidQueryResult) + , FrameNumber(-1) + , bInsideQuery(false) + { + StatName = InStatId.GetName(); + } + + void Begin(FRHICommandListImmediate& RHICmdList) + { + check(IsInRenderingThread()); + check(!bInsideQuery); + bInsideQuery = true; + + if (!StartQuery) + { + StartQuery = RHICmdList.CreateRenderQuery(RQT_AbsoluteTime); + EndQuery = RHICmdList.CreateRenderQuery(RQT_AbsoluteTime); + } + + RHICmdList.EndRenderQuery(StartQuery); + StartResultMicroseconds = InvalidQueryResult; + EndResultMicroseconds = InvalidQueryResult; + FrameNumber = GFrameNumberRenderThread; + } + + void End(FRHICommandListImmediate& RHICmdList) + { + check(IsInRenderingThread()); + check(bInsideQuery); + bInsideQuery = false; + RHICmdList.EndRenderQuery(EndQuery); + } + + bool GatherQueryResults(FRHICommandListImmediate& RHICmdList) + { + // Get the query results which are still outstanding + if (StartResultMicroseconds == InvalidQueryResult) + { + if (!RHICmdList.GetRenderQueryResult(StartQuery, StartResultMicroseconds, false)) + { + StartResultMicroseconds = InvalidQueryResult; + } + } + if (EndResultMicroseconds == InvalidQueryResult) + { + if (!RHICmdList.GetRenderQueryResult(EndQuery, EndResultMicroseconds, false)) + { + EndResultMicroseconds = InvalidQueryResult; + } + } + return HasValidResult(); + } + + float GetResultMS() const + { + check(HasValidResult()); + if (EndResultMicroseconds < StartResultMicroseconds) + { + // This should never happen... + return 0.0f; + } + return float(EndResultMicroseconds - StartResultMicroseconds) / 1000.0f; + } + + bool HasValidResult() const + { + return StartResultMicroseconds != FRealtimeGPUProfilerEvent::InvalidQueryResult && EndResultMicroseconds != FRealtimeGPUProfilerEvent::InvalidQueryResult; + } + + const FName& GetStatName() const + { + return StatName; + } + +private: + FRenderQueryRHIRef StartQuery; + FRenderQueryRHIRef EndQuery; + FName StatName; + uint64 StartResultMicroseconds; + uint64 EndResultMicroseconds; + uint32 FrameNumber; + + bool bInsideQuery; +}; + +/*----------------------------------------------------------------------------- +FRealtimeGPUProfilerFrame class +Container for a single frame's GPU stats +-----------------------------------------------------------------------------*/ +class FRealtimeGPUProfilerFrame +{ +public: + FRealtimeGPUProfilerFrame() + : FrameNumber(-1) + {} + + ~FRealtimeGPUProfilerFrame() + { + Clear(); + } + + void PushEvent(FRHICommandListImmediate& RHICmdList, TStatId StatId) + { +#if GPU_STATS_CHILD_TIMES_INCLUDED == 0 + if (EventStack.Num() > 0) + { + // GPU Stats are not hierarchical. If we already have an event in the stack, + // we need end it and resume it once the child event completes + FRealtimeGPUProfilerEvent* ParentEvent = EventStack.Last(); + ParentEvent->End(RHICmdList); + } +#endif + FRealtimeGPUProfilerEvent* Event = CreateNewEvent(StatId); + EventStack.Push(Event); + StatStack.Push(StatId); + Event->Begin(RHICmdList); + } + + void PopEvent(FRHICommandListImmediate& RHICmdList) + { + FRealtimeGPUProfilerEvent* Event = EventStack.Pop(); + StatStack.Pop(); + Event->End(RHICmdList); + +#if GPU_STATS_CHILD_TIMES_INCLUDED == 0 + if (EventStack.Num() > 0) + { + // Resume the parent event (requires creation of a new FRealtimeGPUProfilerEvent) + TStatId PrevStatId = StatStack.Last(); + FRealtimeGPUProfilerEvent* ResumedEvent = CreateNewEvent(PrevStatId); + EventStack.Last() = ResumedEvent; + ResumedEvent->Begin(RHICmdList); + } +#endif + + } + + void Clear() + { + EventStack.Empty(); + StatStack.Empty(); + + for (int Index = 0; Index < GpuProfilerEvents.Num(); Index++) + { + if (GpuProfilerEvents[Index]) + { + delete GpuProfilerEvents[Index]; + } + } + GpuProfilerEvents.Empty(); + } + + bool UpdateStats(FRHICommandListImmediate& RHICmdList) + { + // Gather any remaining results and check all the results are ready + for (int Index = 0; Index < GpuProfilerEvents.Num(); Index++) + { + FRealtimeGPUProfilerEvent* Event = GpuProfilerEvents[Index]; + check(Event != nullptr); + if (!Event->HasValidResult()) + { + Event->GatherQueryResults(RHICmdList); + } + if (!Event->HasValidResult()) + { + // The frame isn't ready yet. Don't update stats - we'll try again next frame. + return false; + } + } + + float TotalMS = 0.0f; + // Update the stats + TMap StatSeenMap; + for (int Index = 0; Index < GpuProfilerEvents.Num(); Index++) + { + FRealtimeGPUProfilerEvent* Event = GpuProfilerEvents[Index]; + check(Event != nullptr); + check(Event->HasValidResult()); + EStatOperation::Type StatOp; + const FName& StatName = Event->GetStatName(); + + // Check if we've seen this stat yet + if (StatSeenMap.Find(StatName) == nullptr) + { + StatSeenMap.Add(StatName, true); + StatOp = EStatOperation::Set; + } + else + { + // Stat was seen before, so accumulate + StatOp = EStatOperation::Add; + } + float ResultMS = Event->GetResultMS(); + FThreadStats::AddMessage(StatName, StatOp, double(ResultMS)); + TotalMS += ResultMS; + } + + FThreadStats::AddMessage( GET_STATFNAME(Stat_GPU_Total), EStatOperation::Set, double(TotalMS) ); + return true; + } + +private: + FRealtimeGPUProfilerEvent* CreateNewEvent(const TStatId& StatId) + { + FRealtimeGPUProfilerEvent* NewEvent = new FRealtimeGPUProfilerEvent(StatId); + GpuProfilerEvents.Add(NewEvent); + return NewEvent; + } + + TArray GpuProfilerEvents; + TArray EventStack; + TArray StatStack; + uint32 FrameNumber; +}; + +/*----------------------------------------------------------------------------- +FRealtimeGPUProfiler +-----------------------------------------------------------------------------*/ +FRealtimeGPUProfiler* FRealtimeGPUProfiler::Instance = nullptr; + +FRealtimeGPUProfiler* FRealtimeGPUProfiler::Get() +{ + if (Instance == nullptr) + { + Instance = new FRealtimeGPUProfiler; + } + return Instance; +} + +FRealtimeGPUProfiler::FRealtimeGPUProfiler() + : WriteBufferIndex(-1) + , ReadBufferIndex(-1) + , WriteFrameNumber(-1) +{ + for (int Index = 0; Index < NumGPUProfilerBufferedFrames; Index++) + { + Frames.Add(new FRealtimeGPUProfilerFrame()); + } +} + +void FRealtimeGPUProfiler::Release() +{ + for (int Index = 0; Index < Frames.Num(); Index++) + { + delete Frames[Index]; + } + Frames.Empty(); +} + +void FRealtimeGPUProfiler::Update(FRHICommandListImmediate& RHICmdList) +{ + check(Frames.Num() > 0); + if (WriteFrameNumber == GFrameNumberRenderThread) + { + // Multiple views: only update if this is a new frame. Otherwise we just concatenate the stats + return; + } + WriteFrameNumber = GFrameNumberRenderThread; + WriteBufferIndex = (WriteBufferIndex + 1) % Frames.Num(); + Frames[WriteBufferIndex]->Clear(); + + // If the write buffer catches the read buffer, we need to advance the read buffer before we write over it + if (WriteBufferIndex == ReadBufferIndex) + { + ReadBufferIndex = (ReadBufferIndex - 1) % Frames.Num(); + } + UpdateStats(RHICmdList); +} + +void FRealtimeGPUProfiler::PushEvent(FRHICommandListImmediate& RHICmdList, TStatId StatId) +{ + check(Frames.Num() > 0); + if (WriteBufferIndex >= 0) + { + Frames[WriteBufferIndex]->PushEvent(RHICmdList, StatId); + } +} + +void FRealtimeGPUProfiler::PopEvent(FRHICommandListImmediate& RHICmdList) +{ + check(Frames.Num() > 0); + if (WriteBufferIndex >= 0) + { + Frames[WriteBufferIndex]->PopEvent(RHICmdList); + } +} + +void FRealtimeGPUProfiler::UpdateStats(FRHICommandListImmediate& RHICmdList) +{ + check(IsInRenderingThread()); + if (GSupportsTimestampRenderQueries == false || !CVarGPUStatsEnabled.GetValueOnRenderThread() ) + { + return; + } + check(Frames.Num() > 0); + bool bAdvanceReadIndex = false; + if (ReadBufferIndex == -1) + { + bAdvanceReadIndex = true; + } + else + { + // If the read frame is valid, update the stats + if (Frames[ReadBufferIndex]->UpdateStats(RHICmdList)) + { + // On a successful read, advance the ReadBufferIndex + bAdvanceReadIndex = true; + } + } + if (bAdvanceReadIndex) + { + ReadBufferIndex = (ReadBufferIndex + 1) % Frames.Num(); + } +} + +/*----------------------------------------------------------------------------- +FScopedGPUStatEvent +-----------------------------------------------------------------------------*/ +void FScopedGPUStatEvent::Begin(FRHICommandList& InRHICmdList, TStatId InStatID) +{ + check(IsInRenderingThread()); + if (GSupportsTimestampRenderQueries == false || !CVarGPUStatsEnabled.GetValueOnRenderThread()) + { + return; + } + + // Non-immediate commandlists are not supported (silently fail) + if (InRHICmdList.IsImmediate()) + { + RHICmdList = (FRHICommandListImmediate*)&InRHICmdList; + FRealtimeGPUProfiler::Get()->PushEvent(*RHICmdList, InStatID); + } +} + +void FScopedGPUStatEvent::End() +{ + check(IsInRenderingThread()); + if (GSupportsTimestampRenderQueries == false || !CVarGPUStatsEnabled.GetValueOnRenderThread() ) + { + return; + } + if (RHICmdList != nullptr) + { + FRealtimeGPUProfiler::Get()->PopEvent(*RHICmdList); + } +} +#endif // HAS_GPU_STATS diff --git a/Engine/Source/Runtime/Engine/Private/ShaderCompiler/ShaderCompiler.cpp b/Engine/Source/Runtime/Engine/Private/ShaderCompiler/ShaderCompiler.cpp index 1efa258598fb..597ff49e4b3b 100644 --- a/Engine/Source/Runtime/Engine/Private/ShaderCompiler/ShaderCompiler.cpp +++ b/Engine/Source/Runtime/Engine/Private/ShaderCompiler/ShaderCompiler.cpp @@ -2395,8 +2395,8 @@ void GlobalBeginCompileShader( // List mostly comes from set of characters not allowed by windows in a path. Just try to rename a file and type one of these for the list. Input.DumpDebugInfoPath.ReplaceInline(TEXT("<"), TEXT("(")); Input.DumpDebugInfoPath.ReplaceInline(TEXT(">"), TEXT(")")); - Input.DumpDebugInfoPath.ReplaceInline(TEXT("::"), TEXT("==")); - Input.DumpDebugInfoPath.ReplaceInline(TEXT("|"), TEXT("_")); + Input.DumpDebugInfoPath.ReplaceInline(TEXT("::"), TEXT("==")); + Input.DumpDebugInfoPath.ReplaceInline(TEXT("|"), TEXT("_")); Input.DumpDebugInfoPath.ReplaceInline(TEXT("*"), TEXT("-")); Input.DumpDebugInfoPath.ReplaceInline(TEXT("?"), TEXT("!")); Input.DumpDebugInfoPath.ReplaceInline(TEXT("\""), TEXT("\'")); @@ -2409,12 +2409,12 @@ void GlobalBeginCompileShader( // Add the appropriate definitions for the shader frequency. { - Input.Environment.SetDefine(TEXT("PIXELSHADER"), Target.Frequency == SF_Pixel); - Input.Environment.SetDefine(TEXT("DOMAINSHADER"), Target.Frequency == SF_Domain); - Input.Environment.SetDefine(TEXT("HULLSHADER"), Target.Frequency == SF_Hull); - Input.Environment.SetDefine(TEXT("VERTEXSHADER"), Target.Frequency == SF_Vertex); - Input.Environment.SetDefine(TEXT("GEOMETRYSHADER"), Target.Frequency == SF_Geometry); - Input.Environment.SetDefine(TEXT("COMPUTESHADER"), Target.Frequency == SF_Compute); + Input.Environment.SetDefine(TEXT("PIXELSHADER"), Target.Frequency == SF_Pixel); + Input.Environment.SetDefine(TEXT("DOMAINSHADER"), Target.Frequency == SF_Domain); + Input.Environment.SetDefine(TEXT("HULLSHADER"), Target.Frequency == SF_Hull); + Input.Environment.SetDefine(TEXT("VERTEXSHADER"), Target.Frequency == SF_Vertex); + Input.Environment.SetDefine(TEXT("GEOMETRYSHADER"), Target.Frequency == SF_Geometry); + Input.Environment.SetDefine(TEXT("COMPUTESHADER"), Target.Frequency == SF_Compute); } // Set instanced stereo define @@ -2454,7 +2454,7 @@ void GlobalBeginCompileShader( Input.Environment.CompilerFlags.Add(CFLAG_Debug); } } - + { static const auto CVar = IConsoleManager::Get().FindConsoleVariable(TEXT("r.Shaders.KeepDebugInfo")); @@ -2487,7 +2487,7 @@ void GlobalBeginCompileShader( { FString ShaderPDBRoot; GConfig->GetString(TEXT("DevOptions.Shaders"), TEXT("ShaderPDBRoot"), ShaderPDBRoot, GEngineIni); - if ( !ShaderPDBRoot.IsEmpty() ) + if (!ShaderPDBRoot.IsEmpty()) { Input.Environment.SetDefine(TEXT("SHADER_PDB_ROOT"), *ShaderPDBRoot); } @@ -2503,7 +2503,7 @@ void GlobalBeginCompileShader( Input.Environment.SetDefine(TEXT("DXT5_NORMALMAPS"), CVar ? (CVar->GetValueOnGameThread() != 0) : 0); } - if(bAllowDevelopmentShaderCompile) + if (bAllowDevelopmentShaderCompile) { static const auto CVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.CompileShadersForDevelopment")); Input.Environment.SetDefine(TEXT("COMPILE_SHADERS_FOR_DEVELOPMENT"), CVar ? (CVar->GetValueOnGameThread() != 0) : 0); @@ -2539,6 +2539,15 @@ void GlobalBeginCompileShader( Input.Environment.SetDefine(TEXT("FORWARD_SHADING"), CVar ? (CVar->GetInt() != 0) : 0); } + if (GSupportsRenderTargetWriteMask) + { + Input.Environment.SetDefine(TEXT("PLATFORM_SUPPORTS_RENDERTARGET_WRITE_MASK"), 1); + } + else + { + Input.Environment.SetDefine(TEXT("PLATFORM_SUPPORTS_RENDERTARGET_WRITE_MASK"), 0); + } + NewJobs.Add(NewJob); } diff --git a/Engine/Source/Runtime/Engine/Private/SkeletalRenderCPUSkin.cpp b/Engine/Source/Runtime/Engine/Private/SkeletalRenderCPUSkin.cpp index 5f653161e4f1..1946937d1bb2 100644 --- a/Engine/Source/Runtime/Engine/Private/SkeletalRenderCPUSkin.cpp +++ b/Engine/Source/Runtime/Engine/Private/SkeletalRenderCPUSkin.cpp @@ -23,6 +23,7 @@ #include "EnginePrivate.h" #include "SkeletalRenderCPUSkin.h" #include "Animation/MorphTarget.h" +#include "GPUSkinVertexFactory.h" struct FMorphTargetDelta; @@ -807,11 +808,11 @@ static void SkinVertices(FFinalSkinVertex* DestVertex, FMatrix* ReferenceToLocal TArray MorphEvalInfos; uint32 NumValidMorphs = InitEvalInfos(ActiveMorphTargets, MorphTargetWeights, LODIndex, MorphEvalInfos); - static const auto MaxBonesVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("Compat.MAX_GPUSKIN_BONES")); - const int32 MaxGPUSkinBones = MaxBonesVar->GetValueOnAnyThread(); + const uint32 MaxGPUSkinBones = FGPUBaseSkinVertexFactory::GetMaxGPUSkinBones(); + check(MaxGPUSkinBones <= FGPUBaseSkinVertexFactory::GHardwareMaxGPUSkinBones); // Prefetch all matrices - for ( int32 MatrixIndex=0; MatrixIndex < MaxGPUSkinBones; MatrixIndex+=2 ) + for ( uint32 MatrixIndex=0; MatrixIndex < MaxGPUSkinBones; MatrixIndex+=2 ) { FPlatformMisc::Prefetch( ReferenceToLocal + MatrixIndex ); } diff --git a/Engine/Source/Runtime/Engine/Private/Streaming/AsyncTextureStreaming.cpp b/Engine/Source/Runtime/Engine/Private/Streaming/AsyncTextureStreaming.cpp index b7283a8250ae..9a9952a48b66 100644 --- a/Engine/Source/Runtime/Engine/Private/Streaming/AsyncTextureStreaming.cpp +++ b/Engine/Source/Runtime/Engine/Private/Streaming/AsyncTextureStreaming.cpp @@ -210,12 +210,50 @@ void FAsyncTextureStreamingTask::UpdateBudgetedMips_Async(int64& MemoryUsed, int // Sort texture, having those that should be dropped first. PrioritizedTextures.Sort(FCompareTextureByRetentionPriority(StreamingTextures)); - bool bBudgetIsChanging = true; - int32 NumDroppedMips = 0; - while (MemoryBudgeted > MemoryBudget && bBudgetIsChanging && !IsAborted()) + // When using mip bias per texture, we first reduce the maximum resolutions (if used) in order to fit. + for (int32 NumDroppedMips = 0; NumDroppedMips < MaxPerTextureMipBias && MemoryBudgeted > MemoryBudget && !IsAborted(); ++NumDroppedMips) { - bBudgetIsChanging = false; - ++NumDroppedMips; + bool bBudgetCanChange = false; + + for (int32 PriorityIndex = PrioritizedTextures.Num() - 1; PriorityIndex >= 0 && MemoryBudgeted > MemoryBudget && !IsAborted(); --PriorityIndex) + { + int32 TextureIndex = PrioritizedTextures[PriorityIndex]; + if (TextureIndex == INDEX_NONE) continue; + + FStreamingTexture& StreamingTexture = StreamingTextures[TextureIndex]; + + if (StreamingTexture.BudgetedMips <= StreamingTexture.MinAllowedMips) + { + // Don't try this one again. + PrioritizedTextures[PriorityIndex] = INDEX_NONE; + continue; + } + else + { + bBudgetCanChange = true; + } + + if (!StreamingTexture.IsMaxResolutionAffectedByGlobalBias()) continue; + + // If the texture requires a high resolution mip, consider dropping it. + // When considering dropping the first mip, only textures using the first mip will drop their resolution, + // But when considering dropping the second mip, textures using their first and second mips will loose it. + if (StreamingTexture.MaxAllowedMips + StreamingTexture.BudgetMipBias - NumDroppedMips <= StreamingTexture.BudgetedMips) + { + MemoryBudgeted -= StreamingTexture.DropMaxResolution_Async(NumDroppedMips + 1 - StreamingTexture.BudgetMipBias); + } + } + + if (!bBudgetCanChange) + { + break; + } + } + + // Then reduce all resolution. + while (MemoryBudgeted > MemoryBudget && !IsAborted()) + { + bool bBudgetCanChange = false; // Drop from the lowest priority first (starting with last elements) for (int32 PriorityIndex = PrioritizedTextures.Num() - 1; PriorityIndex >= 0 && MemoryBudgeted > MemoryBudget && !IsAborted(); --PriorityIndex) @@ -225,24 +263,30 @@ void FAsyncTextureStreamingTask::UpdateBudgetedMips_Async(int64& MemoryUsed, int FStreamingTexture& StreamingTexture = StreamingTextures[TextureIndex]; - // If this texture has already missing mips for its normal quality, don't drop more than required.. - if (StreamingTexture.NumMissingMips >= NumDroppedMips) + if (StreamingTexture.BudgetedMips <= StreamingTexture.MinAllowedMips) { - bBudgetIsChanging = true; // Needed to prevent aborting loop. + // Don't try this one again. + PrioritizedTextures[PriorityIndex] = INDEX_NONE; + continue; + } + else + { + bBudgetCanChange = true; + } + + // If this texture has already missing mips for its normal quality, don't drop more than required.. + if (StreamingTexture.NumMissingMips > 0) + { + --StreamingTexture.NumMissingMips; continue; } - int64 GivenMemory = StreamingTexture.DropOneMip_Async(MaxPerTextureMipBias); + MemoryBudgeted -= StreamingTexture.DropOneMip_Async(MaxPerTextureMipBias); + } - if (GivenMemory > 0) - { - MemoryBudgeted -= GivenMemory; - bBudgetIsChanging = true; - } - else // Nothing to drop - { - PrioritizedTextures[PriorityIndex] = INDEX_NONE; // Don't try this one again. - } + if (!bBudgetCanChange) + { + break; } } } @@ -432,6 +476,7 @@ void FAsyncTextureStreamingTask::UpdateStats_Async() #if STATS FTextureStreamingStats& Stats = StreamingManager.GatheredStats; FTextureStreamingStats& PrevStats = StreamingManager.DisplayedStats; + FTextureStreamingSettings& Settings = StreamingManager.Settings; TArray& StreamingTextures = StreamingManager.StreamingTextures; Stats.TexturePool = PoolSize; diff --git a/Engine/Source/Runtime/Engine/Private/Streaming/StreamingManagerTexture.cpp b/Engine/Source/Runtime/Engine/Private/Streaming/StreamingManagerTexture.cpp index 806ecec88ace..b1fcb8ccec9e 100644 --- a/Engine/Source/Runtime/Engine/Private/Streaming/StreamingManagerTexture.cpp +++ b/Engine/Source/Runtime/Engine/Private/Streaming/StreamingManagerTexture.cpp @@ -493,7 +493,10 @@ void FStreamingManagerTexture::AddStreamingTexture( UTexture2D* Texture ) { // Adds the new texture to the Pending list, to avoid reallocation of the thread-safe StreamingTextures array. check(Texture->StreamingIndex == INDEX_NONE); - Texture->StreamingIndex = PendingStreamingTextures.Add(Texture);; + Texture->StreamingIndex = PendingStreamingTextures.Add(Texture); + + // Notify that this texture ptr is valid. + ReferencedTextures.Add(Texture); } /** @@ -515,6 +518,9 @@ void FStreamingManagerTexture::RemoveStreamingTexture( UTexture2D* Texture ) } Texture->StreamingIndex = INDEX_NONE; + + // Remove reference to this texture. + ReferencedTextures.Remove(Texture); } /** Called when an actor is spawned. */ @@ -603,7 +609,12 @@ void FStreamingManagerTexture::SetTexturesRemovedTimestamp(const FRemovedTexture const double CurrentTime = FApp::GetCurrentTime(); for ( int32 TextureIndex=0; TextureIndex < RemovedTextures.Num(); ++TextureIndex ) { - FStreamingTexture* StreamingTexture = GetStreamingTexture( RemovedTextures[TextureIndex] ); + // When clearing references to textures, those textures could be already deleted. + // This happens because we don't clear texture references in RemoveStreamingTexture. + const UTexture2D* Texture = RemovedTextures[TextureIndex]; + if (!ReferencedTextures.Contains(Texture)) continue; + + FStreamingTexture* StreamingTexture = GetStreamingTexture(Texture); if ( StreamingTexture ) { StreamingTexture->InstanceRemovedTimestamp = CurrentTime; diff --git a/Engine/Source/Runtime/Engine/Private/Streaming/StreamingManagerTexture.h b/Engine/Source/Runtime/Engine/Private/Streaming/StreamingManagerTexture.h index ec7d9189ee0f..7621735b098f 100644 --- a/Engine/Source/Runtime/Engine/Private/Streaming/StreamingManagerTexture.h +++ b/Engine/Source/Runtime/Engine/Private/Streaming/StreamingManagerTexture.h @@ -218,6 +218,9 @@ protected: /** All streaming UTexture2D objects. */ TArray StreamingTextures; + /** All the textures referenced in StreamingTextures. Used to handled deleted textures. */ + TSet ReferencedTextures; + /** Index of the StreamingTexture that will be updated next by UpdateStreamingTextures(). */ int32 CurrentUpdateStreamingTextureIndex; //END: Thread-safe functions and data diff --git a/Engine/Source/Runtime/Engine/Private/Streaming/StreamingTexture.cpp b/Engine/Source/Runtime/Engine/Private/Streaming/StreamingTexture.cpp index c111b7f3a03c..cb483c571b93 100644 --- a/Engine/Source/Runtime/Engine/Private/Streaming/StreamingTexture.cpp +++ b/Engine/Source/Runtime/Engine/Private/Streaming/StreamingTexture.cpp @@ -89,7 +89,7 @@ void FStreamingTexture::UpdateDynamicData(const int32 NumStreamedMips[TEXTUREGRO LODBias = FMath::Max(Texture->GetCachedLODBias() - NumCinematicMipLevels, 0); // Reduce the max allowed resolution according to LODBias if the texture group allows it. - if (LODGroup != TEXTUREGROUP_HierarchicalLOD && !bIsTerrainTexture) + if (IsMaxResolutionAffectedByGlobalBias()) { LODBias += Settings.GlobalMipBiasAsInt(); } @@ -166,8 +166,7 @@ void FStreamingTexture::UpdateStreamingStatus() float FStreamingTexture::GetExtraBoost(TextureGroup LODGroup, const FTextureStreamingSettings& Settings) { // When accurate distance computation, we need to relax the distance otherwhise it get's too conservative. (ex 513 goes to 1024) - const bool bUseApproxDistance = CVarStreamingUseNewMetrics.GetValueOnAnyThread() == 0; - const float DistanceScale = bUseApproxDistance ? 1.f : .71f; + const float DistanceScale = Settings.bUseNewMetrics ? .71f : 1.f; if (LODGroup == TEXTUREGROUP_Terrain_Heightmap || LODGroup == TEXTUREGROUP_Terrain_Weightmap) { @@ -203,18 +202,17 @@ void FStreamingTexture::SetPerfectWantedMips_Async(float MaxSize, float MaxSize_ VisibleWantedMips = GetWantedMipsFromSize(MaxSize_VisibleOnly); bLooksLowRes = InLooksLowRes; // Things like lightmaps, HLOD and close instances. - // Here BudgetMipBias is added to NumMissingMips to prevent the same texture from dropping resolution too early (as it is already included in MaxMip) - // Terrain, Forced Fully Load and Things that already look bad are not affected by hidden scale. if (bIsTerrainTexture || bForceFullyLoadHeuristic || bLooksLowRes) { HiddenWantedMips = GetWantedMipsFromSize(MaxSize); - NumMissingMips = BudgetMipBias; // No impact for terrains as there are not allowed to drop mips. + NumMissingMips = 0; // No impact for terrains as there are not allowed to drop mips. } else { HiddenWantedMips = GetWantedMipsFromSize(MaxSize * Settings.HiddenPrimitiveScale); - NumMissingMips = BudgetMipBias + FMath::Max(GetWantedMipsFromSize(MaxSize) - FMath::Max(VisibleWantedMips, HiddenWantedMips), 0); + // NumMissingMips contains the number of mips not loaded because of HiddenPrimitiveScale. When out of budget, those texture will be considered as already sacrificed. + NumMissingMips = FMath::Max(GetWantedMipsFromSize(MaxSize) - FMath::Max(VisibleWantedMips, HiddenWantedMips), 0); } } @@ -250,22 +248,38 @@ int64 FStreamingTexture::UpdateRetentionPriority_Async() } } +int64 FStreamingTexture::DropMaxResolution_Async(int32 NumDroppedMips) +{ + if (Texture) + { + // Don't drop bellow min allowed mips. + NumDroppedMips = FMath::Min(MaxAllowedMips - MinAllowedMips, NumDroppedMips); + + if (NumDroppedMips > 0) + { + // Decrease MaxAllowedMips and increase BudgetMipBias (as it should include it) + MaxAllowedMips -= NumDroppedMips; + BudgetMipBias += NumDroppedMips; + + if (BudgetedMips > MaxAllowedMips) + { + const int64 FreedMemory = GetSize(BudgetedMips) - GetSize(MaxAllowedMips); + + BudgetedMips = MaxAllowedMips; + VisibleWantedMips = FMath::Min(VisibleWantedMips, MaxAllowedMips); + HiddenWantedMips = FMath::Min(HiddenWantedMips, MaxAllowedMips); + + return FreedMemory; + } + } + } + return 0; +} + int64 FStreamingTexture::DropOneMip_Async(int32 MaxPerTextureMipBias) { if (Texture && BudgetedMips > MinAllowedMips) { - // Every time we are required to DropOneMip from max resolution, this increase the BudgetMipBias. - if (BudgetedMips == MaxAllowedMips && VisibleWantedMips == MaxAllowedMips && BudgetMipBias < MaxPerTextureMipBias) - { - // Decrease MaxAllowedMips and increase BudgetMipBias (as it should include it) - --MaxAllowedMips; - ++BudgetMipBias; - - // Update the wanted mips as if they were computed with the new MaxAllowedMips. (for stats) - VisibleWantedMips = FMath::Min(VisibleWantedMips, MaxAllowedMips); - HiddenWantedMips = FMath::Min(HiddenWantedMips, MaxAllowedMips); - } - --BudgetedMips; return GetSize(BudgetedMips + 1) - GetSize(BudgetedMips); } diff --git a/Engine/Source/Runtime/Engine/Private/Streaming/StreamingTexture.h b/Engine/Source/Runtime/Engine/Private/Streaming/StreamingTexture.h index c93f4bd6bb03..452233298f2c 100644 --- a/Engine/Source/Runtime/Engine/Private/Streaming/StreamingTexture.h +++ b/Engine/Source/Runtime/Engine/Private/Streaming/StreamingTexture.h @@ -48,6 +48,9 @@ struct FStreamingTexture /** Init BudgetedMip and update RetentionPriority. Returns the size that would be taken if all budgeted mips where loaded. */ int64 UpdateRetentionPriority_Async(); + /** Reduce the maximum allowed resolution by 1 mip. Return the size freed by doing so. */ + int64 DropMaxResolution_Async(int32 NumDroppedMips); + /** Reduce BudgetedMip by 1 and return the size freed by doing so. */ int64 DropOneMip_Async(int32 MaxPerTextureMipBias = 0); @@ -64,6 +67,9 @@ struct FStreamingTexture FORCEINLINE int32 GetPerfectWantedMips() const { return FMath::Max(VisibleWantedMips, HiddenWantedMips); } + // Whether this texture can be affected by Global Bias and Budget Bias per texture. + FORCEINLINE bool IsMaxResolutionAffectedByGlobalBias() const { return LODGroup != TEXTUREGROUP_HierarchicalLOD && !bIsTerrainTexture; } + /*************************************************************** * Members initialized when this is constructed => NEVER CHANGES ***************************************************************/ diff --git a/Engine/Source/Runtime/Engine/Private/UserInterface/Canvas.cpp b/Engine/Source/Runtime/Engine/Private/UserInterface/Canvas.cpp index bb9b1540af6a..1a98a6d672ad 100644 --- a/Engine/Source/Runtime/Engine/Private/UserInterface/Canvas.cpp +++ b/Engine/Source/Runtime/Engine/Private/UserInterface/Canvas.cpp @@ -1372,6 +1372,8 @@ ESimpleElementBlendMode FCanvas::BlendToSimpleElementBlend(EBlendMode BlendMode) return SE_BLEND_Additive; case BLEND_Modulate: return SE_BLEND_Modulate; + case BLEND_AlphaComposite: + return SE_BLEND_AlphaComposite; case BLEND_Translucent: default: return SE_BLEND_Translucent; diff --git a/Engine/Source/Runtime/Engine/Public/PixelFormat.h b/Engine/Source/Runtime/Engine/Public/PixelFormat.h index f72fabdd8d76..3ab9f5200cfd 100644 --- a/Engine/Source/Runtime/Engine/Public/PixelFormat.h +++ b/Engine/Source/Runtime/Engine/Public/PixelFormat.h @@ -62,7 +62,8 @@ enum EPixelFormat PF_ASTC_12x12 =54, // 0.89 bpp PF_BC6H =55, PF_BC7 =56, - PF_MAX =57, + PF_R8_UINT =57, + PF_MAX =58, }; #define FOREACH_ENUM_EPIXELFORMAT(op) \ op(PF_Unknown) \ @@ -120,5 +121,6 @@ enum EPixelFormat op(PF_ASTC_10x10) \ op(PF_ASTC_12x12) \ op(PF_BC6H) \ - op(PF_BC7) + op(PF_BC7) \ + op(PF_R8_UINT) diff --git a/Engine/Source/Runtime/Engine/Public/SceneManagement.h b/Engine/Source/Runtime/Engine/Public/SceneManagement.h index a7a5b683778f..d889e23a733a 100644 --- a/Engine/Source/Runtime/Engine/Public/SceneManagement.h +++ b/Engine/Source/Runtime/Engine/Public/SceneManagement.h @@ -1023,6 +1023,9 @@ public: */ virtual void ApplyWorldOffset(FVector InOffset); + virtual float GetMaxDrawDistance() const { return 0.0f; } + virtual float GetFadeRange() const { return 0.0f; } + protected: friend class FScene; diff --git a/Engine/Source/Runtime/Engine/Public/SceneUtils.h b/Engine/Source/Runtime/Engine/Public/SceneUtils.h index 1b3ac0e71880..a5470b17f608 100644 --- a/Engine/Source/Runtime/Engine/Public/SceneUtils.h +++ b/Engine/Source/Runtime/Engine/Public/SceneUtils.h @@ -147,6 +147,95 @@ #endif +// GPU stats +#if STATS +#define HAS_GPU_STATS 1 +#else +#define HAS_GPU_STATS 0 +#endif + +#if HAS_GPU_STATS +#define SCOPED_GPU_STAT(RHICmdList, Stat) FScopedGPUStatEvent PREPROCESSOR_JOIN(GPUStatEvent_##Stat,__LINE__); PREPROCESSOR_JOIN(GPUStatEvent_##Stat,__LINE__).Begin(RHICmdList, GET_STATID( Stat ) ); +#define GPU_STATS_UPDATE(RHICmdList) FRealtimeGPUProfiler::Get()->Update(RHICmdList); +#else +#define SCOPED_GPU_STAT(RHICmdList, Stat) +#define GPU_STATS_UPDATE(RHICmdList) +#endif + +#if HAS_GPU_STATS + +class FRealtimeGPUProfilerEvent; +class FRealtimeGPUProfilerFrame; + +/** +* FRealtimeGPUProfiler class. This manages recording and reporting all for GPU stats +*/ +class FRealtimeGPUProfiler +{ + static FRealtimeGPUProfiler* Instance; +public: + // Singleton interface + static ENGINE_API FRealtimeGPUProfiler* Get(); + + /** Per-frame update */ + ENGINE_API void Update(FRHICommandListImmediate& RHICmdList); + + /** Final cleanup */ + ENGINE_API void Release(); + + /** Push/pop events */ + void PushEvent(FRHICommandListImmediate& RHICmdList, TStatId StatId); + void PopEvent(FRHICommandListImmediate& RHICmdList); + +private: + FRealtimeGPUProfiler(); + void UpdateStats(FRHICommandListImmediate& RHICmdList); + + /** Ringbuffer of profiler frames */ + TArray Frames; + + int32 WriteBufferIndex; + int32 ReadBufferIndex; + uint32 WriteFrameNumber; +}; + +/** +* Class that logs GPU Stat events for the realtime GPU profiler +*/ +class FScopedGPUStatEvent +{ + /** Cmdlist to push onto. */ + FRHICommandListImmediate* RHICmdList; + + /** The stat event used to record timings */ + FRealtimeGPUProfilerEvent* RealtimeGPUProfilerEvent; + +public: + /** Default constructor, initializing all member variables. */ + FORCEINLINE FScopedGPUStatEvent() + : RHICmdList(nullptr) + , RealtimeGPUProfilerEvent(nullptr) + {} + + /** + * Terminate the event based upon scope + */ + FORCEINLINE ~FScopedGPUStatEvent() + { + if (RHICmdList) + { + End(); + } + } + + /** + * Start/Stop functions for timer stats + */ + ENGINE_API void Begin(FRHICommandList& InRHICmdList, TStatId StatID); + ENGINE_API void End(); +}; +#endif // HAS_GPU_STATS + /** True if HDR is enabled for the mobile renderer. */ ENGINE_API bool IsMobileHDR(); diff --git a/Engine/Source/Runtime/Launch/Private/LaunchEngineLoop.cpp b/Engine/Source/Runtime/Launch/Private/LaunchEngineLoop.cpp index 036d6dfbc692..5d6ea67c4266 100644 --- a/Engine/Source/Runtime/Launch/Private/LaunchEngineLoop.cpp +++ b/Engine/Source/Runtime/Launch/Private/LaunchEngineLoop.cpp @@ -201,6 +201,9 @@ static TScopedPointer GScopedTestExit; #if WITH_ENGINE static void RHIExitAndStopRHIThread() { +#if HAS_GPU_STATS + FRealtimeGPUProfiler::Get()->Release(); +#endif RHIExit(); // Stop the RHI Thread diff --git a/Engine/Source/Runtime/Niagara/Classes/NiagaraConstants.h b/Engine/Source/Runtime/Niagara/Classes/NiagaraConstants.h index d54f4bddd809..849dcd26f8a6 100644 --- a/Engine/Source/Runtime/Niagara/Classes/NiagaraConstants.h +++ b/Engine/Source/Runtime/Niagara/Classes/NiagaraConstants.h @@ -17,10 +17,11 @@ namespace NiagaraConstants NumBuiltinConstants } ConstantDef; - FName ConstantNames[] = { + FName GConstantNames[] = { + "Undefined", "Delta Time", - "Emitter position", - "Emitter age", + "Emitter Position", + "Emitter Age", "Emitter X Axis", "Emitter Y Axis", "Emitter Z Axis", @@ -28,3 +29,6 @@ namespace NiagaraConstants }; }; +#define BUILTIN_CONST_DELTATIME NiagaraConstants::GConstantNames[NiagaraConstants::DeltaSeconds] +#define BUILTIN_CONST_EMITTERPOS NiagaraConstants::GConstantNames[NiagaraConstants::EmitterPosition] +#define BUILTIN_CONST_EMITTERAGE NiagaraConstants::GConstantNames[NiagaraConstants::EmitterAge] \ No newline at end of file diff --git a/Engine/Source/Runtime/Niagara/Classes/NiagaraDataSet.h b/Engine/Source/Runtime/Niagara/Classes/NiagaraDataSet.h index a7d3e89bdd1f..ef440a8f8f8a 100644 --- a/Engine/Source/Runtime/Niagara/Classes/NiagaraDataSet.h +++ b/Engine/Source/Runtime/Niagara/Classes/NiagaraDataSet.h @@ -3,7 +3,153 @@ #include "NiagaraCommon.h" -/** Storage for Niagara data. */ +const FName BUILTIN_VAR_PARTICLEAGE = FName(TEXT("Age")); + +#define SEPARATE_PER_VARIABLE_DATA 1 + + + + +/** Niagara Data Buffer + * Holds a number of elements of data of a specific type; set Target to determine + * whether CPU or GPU side + */ +class FNiagaraDataBuffer +{ +public: + FNiagaraDataBuffer() + : DataType(ENiagaraDataType::Vector) + , ElementType(ENiagaraType::Float) + , Target(ENiagaraSimTarget::CPUSim) + { + } + + ENiagaraSimTarget GetTarget() + { + return Target; + } + + // when changing sim target at runtime, make sure to Reset/Alloc + // generally only happens when changing sim type on emitters, case components are usually re-registered and no further work is needed + void SetTarget(ENiagaraSimTarget InTarget) + { + Target = InTarget; + } + + void Allocate(int32 NumElements) + { + uint32 SizePerElement = GetNiagaraBytesPerElement(DataType, ElementType); + uint32 SizeInBytes = NumElements * SizePerElement; + + if (Target == CPUSim) + { + CPUBuffer.AddUninitialized(SizeInBytes); + } + else if (Target == GPUComputeSim) + { + FRHIResourceCreateInfo CreateInfo; + CreateInfo.ClearValueBinding = FClearValueBinding::None; + CreateInfo.BulkData = nullptr; + GPUBuffer = RHICreateStructuredBuffer(SizePerElement, SizeInBytes, BUF_ShaderResource, CreateInfo); + } + } + + void Reset(uint32 NumElements) + { + if (Target == CPUSim) + { + CPUBuffer.Reset(NumElements); + } + else if (Target == GPUComputeSim) + { + FRHIResourceCreateInfo CreateInfo; + uint32 SizePerElement = GetNiagaraBytesPerElement(DataType, ElementType); + uint32 SizeInBytes = NumElements * SizePerElement; + GPUBuffer = RHICreateStructuredBuffer(SizePerElement, SizeInBytes, BUF_ShaderResource, CreateInfo); + } + } + + const TArray& GetCPUBuffer() const + { + return CPUBuffer; + } + + TArray& GetCPUBuffer() + { + return CPUBuffer; + } + + +private: + ENiagaraDataType DataType; + ENiagaraType ElementType; + FStructuredBufferRHIRef GPUBuffer; + TArray CPUBuffer; + ENiagaraSimTarget Target; +}; + + + +/** Storage for a single particle attribute for all particles of one emitter + * We double buffer at this level, so we can avoid copying or explicitly dealing + * with unused attributes. + */ +class FNiagaraVariableData +{ +public: + FNiagaraVariableData() + : CurrentBuffer(0) + , bPassThroughEnabled(false) + {} + + TArray &GetCurrentBuffer() { return DataBuffers[CurrentBuffer].GetCPUBuffer(); } + TArray &GetPrevBuffer() { return DataBuffers[CurrentBuffer ^ 0x1].GetCPUBuffer(); } + + const TArray &GetCurrentBuffer() const { return DataBuffers[CurrentBuffer].GetCPUBuffer(); } + const TArray &GetPrevBuffer() const { return DataBuffers[CurrentBuffer ^ 0x1].GetCPUBuffer(); } + + void Allocate(uint32 NumElements) + { + //DataBuffers[CurrentBuffer].AddUninitialized(NumElements); + DataBuffers[CurrentBuffer].Allocate(NumElements); + } + + void Reset(uint32 NumElements) + { + DataBuffers[CurrentBuffer].Reset(NumElements); + } + + void SwapBuffers() + { + // Passthrough is usually enabled when an attribute is unused during VM execution; + // in this case, we don't swap buffers, to avoid needing to copy source to destination + if (!bPassThroughEnabled) + { + CurrentBuffer ^= 0x1; + } + } + + // Passthrough enabled means no double buffering; to be used for unused attributes only + void EnablePassThrough() { bPassThroughEnabled = true; } + void DisablePassThrough() { bPassThroughEnabled = false; } + + +private: + ENiagaraDataType Type; + uint8 CurrentBuffer; + FNiagaraDataBuffer DataBuffers[2]; + FStructuredBufferRHIRef GPUDataBuffers[2]; + + bool bPassThroughEnabled; +}; + + + + +/** Storage for Niagara data. + * Holds a set of FNiagaraVariableData along with mapping from FNiagaraVariableInfos + * Generally, this is the entire set of particle attributes for one emitter + */ class FNiagaraDataSet { public: @@ -27,12 +173,20 @@ public: { if (bReset) { - DataBuffers[CurrentBuffer].Reset(NumExpectedInstances * VariableMap.Num()); - DataBuffers[CurrentBuffer].AddUninitialized(NumExpectedInstances * VariableMap.Num()); + VariableDataArray.SetNumZeroed(VariableMap.Num()); + for (auto &Data : VariableDataArray) + { + Data.Reset(NumExpectedInstances); + Data.Allocate(NumExpectedInstances); + } } else { - DataBuffers[CurrentBuffer].SetNumUninitialized(NumExpectedInstances * VariableMap.Num()); + VariableDataArray.SetNumUninitialized(VariableMap.Num()); + for (auto &Data : VariableDataArray) + { + Data.Allocate(NumExpectedInstances); + } } DataAllocation[CurrentBuffer] = NumExpectedInstances; @@ -46,32 +200,30 @@ public: DataAllocation[0] = 0; DataAllocation[1] = 0; CurrentBuffer = 0; - DataBuffers[0].Empty(); - DataBuffers[1].Empty(); } FVector4* GetVariableData(const FNiagaraVariableInfo& VariableID, uint32 StartParticle = 0) { const uint32* Offset = VariableMap.Find(VariableID); - return Offset ? DataBuffers[CurrentBuffer].GetData() + (*Offset * DataAllocation[CurrentBuffer]) + StartParticle : NULL; + return Offset ? VariableDataArray[*Offset].GetCurrentBuffer().GetData() + StartParticle : NULL; } const FVector4* GetVariableData(const FNiagaraVariableInfo& VariableID, uint32 StartParticle = 0)const { const uint32* Offset = VariableMap.Find(VariableID); - return Offset ? DataBuffers[CurrentBuffer].GetData() + (*Offset * DataAllocation[CurrentBuffer]) + StartParticle : NULL; + return Offset ? VariableDataArray[*Offset].GetCurrentBuffer().GetData() + StartParticle : NULL; } FVector4* GetPrevVariableData(const FNiagaraVariableInfo& VariableID, uint32 StartParticle = 0) { const uint32* Offset = VariableMap.Find(VariableID); - return Offset ? DataBuffers[CurrentBuffer ^ 0x1].GetData() + (*Offset * DataAllocation[CurrentBuffer ^ 0x1]) + StartParticle : NULL; + return Offset ? VariableDataArray[*Offset].GetPrevBuffer().GetData() + StartParticle : NULL; } const FVector4* GetPrevVariableData(const FNiagaraVariableInfo& VariableID, uint32 StartParticle = 0)const { const uint32* Offset = VariableMap.Find(VariableID); - return Offset ? DataBuffers[CurrentBuffer ^ 0x1].GetData() + (*Offset * DataAllocation[CurrentBuffer ^ 0x1]) + StartParticle : NULL; + return Offset ? VariableDataArray[*Offset].GetPrevBuffer().GetData() + StartParticle : NULL; } void GetVariableData(const FNiagaraVariableInfo& VariableID, FVector4*& PrevBuffer, FVector4*& CurrBuffer, uint32 StartParticle) @@ -79,8 +231,8 @@ public: const uint32* Offset = VariableMap.Find(VariableID); if (Offset) { - PrevBuffer = DataBuffers[CurrentBuffer ^ 0x1].GetData() + (*Offset * DataAllocation[CurrentBuffer ^ 0x1]) + StartParticle; - CurrBuffer = DataBuffers[CurrentBuffer].GetData() + (*Offset * DataAllocation[CurrentBuffer]) + StartParticle; + PrevBuffer = VariableDataArray[*Offset].GetPrevBuffer().GetData() + StartParticle; + CurrBuffer = VariableDataArray[*Offset].GetCurrentBuffer().GetData() + StartParticle; } else { @@ -89,6 +241,14 @@ public: } } + + FNiagaraVariableData &GetVariableBuffer(const FNiagaraVariableInfo& VariableID) + { + const uint32* VarIdx = VariableMap.Find(VariableID); + return VariableDataArray[*VarIdx]; + } + + bool HasAttriubte(const FNiagaraVariableInfo& VariableID) { return VariableMap.Find(VariableID) != NULL; @@ -123,6 +283,7 @@ public: } } + const TMap& GetVariables()const { return VariableMap; } int GetNumVariables() { return VariableMap.Num(); } @@ -133,10 +294,17 @@ public: void SetNumInstances(uint32 Num) { NumInstances[CurrentBuffer] = Num; } void SwapBuffers() { CurrentBuffer ^= 0x1; } - FVector4* GetCurrentBuffer() { return DataBuffers[CurrentBuffer].GetData(); } - FVector4* GetPreviousBuffer() { return DataBuffers[CurrentBuffer ^ 0x1].GetData(); } + FVector4* GetCurrentBuffer(uint32 AttrIndex) { return VariableDataArray[AttrIndex].GetCurrentBuffer().GetData(); } + FVector4* GetPreviousBuffer(uint32 AttrIndex) { return VariableDataArray[AttrIndex].GetPrevBuffer().GetData(); } - int GetBytesUsed() { return (DataBuffers[0].Num() + DataBuffers[1].Num()) * 16 + VariableMap.Num() * 4; } + int GetBytesUsed() + { + if (VariableDataArray.Num() == 0) + { + return 0; + } + return (VariableDataArray[0].GetCurrentBuffer().Num() + VariableDataArray[0].GetPrevBuffer().Num()) * 16 + VariableMap.Num() * 4; + } FNiagaraDataSetID GetID()const { return ID; } void SetID(FNiagaraDataSetID InID) { ID = InID; } @@ -145,6 +313,11 @@ public: { SwapBuffers(); + for (auto &VarData : VariableDataArray) + { + VarData.SwapBuffers(); + } + if (ID.Type == ENiagaraDataSetType::Event) { SetNumInstances(0); @@ -159,10 +332,11 @@ public: private: uint32 CurrentBuffer; - uint32 NumInstances[2]; uint32 DataAllocation[2]; - TArray DataBuffers[2]; + uint32 NumInstances[2]; + TMap VariableMap; FNiagaraDataSetID ID; + TArray VariableDataArray; }; diff --git a/Engine/Source/Runtime/Niagara/Classes/NiagaraEffect.h b/Engine/Source/Runtime/Niagara/Classes/NiagaraEffect.h index b4d805fb78d1..86d234435e96 100644 --- a/Engine/Source/Runtime/Niagara/Classes/NiagaraEffect.h +++ b/Engine/Source/Runtime/Niagara/Classes/NiagaraEffect.h @@ -47,9 +47,6 @@ public: virtual void PostLoad()override; //End UObject Interface private: - UPROPERTY() - TArrayEmitterPropsSerialized_DEPRECATED; - UPROPERTY() TArray EmitterProps; }; @@ -122,17 +119,17 @@ public: void SetConstant(FNiagaraVariableInfo ID, const float Value) { - Constants.SetOrAdd(ID, Value); + InstanceConstants.SetOrAdd(ID.Name, Value); } void SetConstant(FNiagaraVariableInfo ID, const FVector4& Value) { - Constants.SetOrAdd(ID, Value); + InstanceConstants.SetOrAdd(ID.Name, Value); } void SetConstant(FNiagaraVariableInfo ID, const FMatrix& Value) { - Constants.SetOrAdd(ID, Value); + InstanceConstants.SetOrAdd(ID.Name, Value); } void Tick(float DeltaSeconds); @@ -162,7 +159,7 @@ private: float Age; /** Local constant table. */ - FNiagaraConstantMap Constants; + FNiagaraConstants InstanceConstants; TMap ExternalEvents; diff --git a/Engine/Source/Runtime/Niagara/Classes/NiagaraEmitterProperties.h b/Engine/Source/Runtime/Niagara/Classes/NiagaraEmitterProperties.h index 9ce25defc6a6..345bc74d97c8 100644 --- a/Engine/Source/Runtime/Niagara/Classes/NiagaraEmitterProperties.h +++ b/Engine/Source/Runtime/Niagara/Classes/NiagaraEmitterProperties.h @@ -102,40 +102,6 @@ struct FNiagaraEmitterScriptProperties NIAGARA_API void Init(UNiagaraEmitterProperties* EmitterProps); }; -//This struct now only exists for backwards compatibility and should be removed once effects are updated. -USTRUCT() -struct FDeprecatedNiagaraEmitterProperties -{ - GENERATED_USTRUCT_BODY() -public: - UPROPERTY() - FString Name; - UPROPERTY() - bool bIsEnabled; - UPROPERTY() - float SpawnRate; - UPROPERTY() - UNiagaraScript *UpdateScript; - UPROPERTY() - UNiagaraScript *SpawnScript; - UPROPERTY() - UMaterial *Material; - UPROPERTY() - TEnumAsByte RenderModuleType; - UPROPERTY() - float StartTime; - UPROPERTY() - float EndTime; - UPROPERTY() - class UNiagaraEffectRendererProperties *RendererProperties; - UPROPERTY() - FNiagaraConstantMap ExternalConstants; // these are the update script constants from the effect editor; will be added to the emitter's constant map - UPROPERTY() - FNiagaraConstantMap ExternalSpawnConstants; // these are the spawn script constants from the effect editor; will be added to the emitter's constant map - UPROPERTY() - int32 NumLoops; -}; - /** * UNiagaraEmitterProperties stores the attributes of an FNiagaraSimulation * that need to be serialized and are used for its initialization @@ -146,7 +112,6 @@ class UNiagaraEmitterProperties : public UObject GENERATED_UCLASS_BODY() public: NIAGARA_API void Init(); - void InitFromOldStruct(FDeprecatedNiagaraEmitterProperties& OldStruct); //Begin UObject Interface #if WITH_EDITOR diff --git a/Engine/Source/Runtime/Niagara/Classes/NiagaraScript.h b/Engine/Source/Runtime/Niagara/Classes/NiagaraScript.h index d5c58148a009..487e78f42791 100644 --- a/Engine/Source/Runtime/Niagara/Classes/NiagaraScript.h +++ b/Engine/Source/Runtime/Niagara/Classes/NiagaraScript.h @@ -20,6 +20,8 @@ enum class EUnusedAttributeBehaviour : uint8 None, /** The memory for the attribute is set to NIAGARA_INVALID_MEMORY. */ MarkInvalid, + /** The attribute is passed through without double buffering */ + PassThrough, }; USTRUCT() diff --git a/Engine/Source/Runtime/Niagara/Classes/NiagaraSimulation.h b/Engine/Source/Runtime/Niagara/Classes/NiagaraSimulation.h index a0b1ba39dcf4..bf0ba5429f21 100644 --- a/Engine/Source/Runtime/Niagara/Classes/NiagaraSimulation.h +++ b/Engine/Source/Runtime/Niagara/Classes/NiagaraSimulation.h @@ -15,6 +15,7 @@ DECLARE_CYCLE_STAT(TEXT("Tick"), STAT_NiagaraTick, STATGROUP_Niagara); DECLARE_CYCLE_STAT(TEXT("Simulate"), STAT_NiagaraSimulate, STATGROUP_Niagara); DECLARE_CYCLE_STAT(TEXT("Spawn"), STAT_NiagaraSpawn, STATGROUP_Niagara); DECLARE_CYCLE_STAT(TEXT("Kill"), STAT_NiagaraKill, STATGROUP_Niagara); +DECLARE_CYCLE_STAT(TEXT("Register Setup"), STAT_NiagaraSimRegisterSetup, STATGROUP_Niagara); /** * A Niagara particle simulation. @@ -34,14 +35,15 @@ public: void PreTick(); void Tick(float DeltaSeconds); + void TickEvents(float DeltaSeconds); + void KillParticles(); FBox GetBounds() const { return CachedBounds; } FNiagaraDataSet &GetData() { return Data; } - void SetConstants(const FNiagaraConstantMap &InMap) { Constants = InMap; } - FNiagaraConstantMap &GetConstants() { return Constants; } + FNiagaraConstants &GetConstants() { return ExternalConstants; } NiagaraEffectRenderer *GetEffectRenderer() { return EffectRenderer; } @@ -92,7 +94,8 @@ private: ENiagaraTickState TickState; /** Local constant set. */ - FNiagaraConstantMap Constants; + FNiagaraConstants ExternalConstants; + /** particle simulation data */ FNiagaraDataSet Data; /** Keep partial particle spawns from last frame */ @@ -135,14 +138,10 @@ private: /** Util to move a particle */ void MoveParticleToIndex(int32 SrcIndex, int32 DestIndex) { - FVector4 *SrcPtr = Data.GetCurrentBuffer() + SrcIndex; - FVector4 *DestPtr = Data.GetCurrentBuffer() + DestIndex; - for (int32 AttrIndex = 0; AttrIndex < Data.GetNumVariables(); AttrIndex++) { - *DestPtr = *SrcPtr; - DestPtr += Data.GetDataAllocation(); - SrcPtr += Data.GetDataAllocation(); + FVector4 *AttrPtr = Data.GetCurrentBuffer(AttrIndex); + *(AttrPtr+DestIndex) = *(AttrPtr+SrcIndex); } } diff --git a/Engine/Source/Runtime/Niagara/NiagaraConstantSet.h b/Engine/Source/Runtime/Niagara/NiagaraConstantSet.h index 8e2c3fe2daed..fc534e040bb2 100644 --- a/Engine/Source/Runtime/Niagara/NiagaraConstantSet.h +++ b/Engine/Source/Runtime/Niagara/NiagaraConstantSet.h @@ -7,56 +7,6 @@ struct FNiagaraConstants; -/** Runtime storage for emitter overridden constants. Only now a USTRUCT still to support BC */ -USTRUCT() -struct FNiagaraConstantMap -{ - GENERATED_USTRUCT_BODY() -private: - TMap ScalarConstants; - TMap VectorConstants; - TMap MatrixConstants; - -public: - FNiagaraConstantMap() - { - } - - void Empty(); - - void SetOrAdd(FNiagaraVariableInfo ID, float Sc); - void SetOrAdd(FNiagaraVariableInfo ID, const FVector4& Vc); - void SetOrAdd(FNiagaraVariableInfo ID, const FMatrix& Mc); - void SetOrAdd(FName Name, float Sc); - void SetOrAdd(FName Name, const FVector4& Vc); - void SetOrAdd(FName Name, const FMatrix& Mc); - - float* FindScalar(FNiagaraVariableInfo ID); - FVector4* FindVector(FNiagaraVariableInfo ID); - FMatrix* FindMatrix(FNiagaraVariableInfo ID); - const float* FindScalar(FNiagaraVariableInfo ID)const; - const FVector4* FindVector(FNiagaraVariableInfo ID)const; - const FMatrix* FindMatrix(FNiagaraVariableInfo ID)const; - float* FindScalar(FName Name); - FVector4* FindVector(FName Name); - FMatrix* FindMatrix(FName Name); - const float* FindScalar(FName Name)const; - const FVector4* FindVector(FName Name)const; - const FMatrix* FindMatrix(FName Name)const; - - void Merge(FNiagaraConstants &InConstants); - void Merge(FNiagaraConstantMap &InMap); - - const TMap &GetScalarConstants() const; - const TMap &GetVectorConstants() const; - const TMap &GetMatrixConstants() const; - - - virtual bool Serialize(FArchive &Ar) - { - return true; - } -}; USTRUCT() struct FNiagaraConstantBase @@ -76,15 +26,15 @@ struct FNiagaraConstantBase }; USTRUCT() -struct FNiagaraConstants_Float : public FNiagaraConstantBase +struct FNiagaraConstant_Float : public FNiagaraConstantBase { GENERATED_USTRUCT_BODY() - FNiagaraConstants_Float() + FNiagaraConstant_Float() : Value(0.0f) {} - FNiagaraConstants_Float(FName InName, float InValue) + FNiagaraConstant_Float(FName InName, float InValue) : FNiagaraConstantBase(InName) , Value(InValue) {} @@ -94,15 +44,15 @@ struct FNiagaraConstants_Float : public FNiagaraConstantBase }; USTRUCT() -struct FNiagaraConstants_Vector : public FNiagaraConstantBase +struct FNiagaraConstant_Vector : public FNiagaraConstantBase { GENERATED_USTRUCT_BODY() - FNiagaraConstants_Vector() + FNiagaraConstant_Vector() : Value(FVector4(1.0f, 1.0f, 1.0f, 1.0f)) {} - FNiagaraConstants_Vector(FName InName, const FVector4& InValue) + FNiagaraConstant_Vector(FName InName, const FVector4& InValue) : FNiagaraConstantBase(InName) , Value(InValue) {} @@ -112,15 +62,15 @@ struct FNiagaraConstants_Vector : public FNiagaraConstantBase }; USTRUCT() -struct FNiagaraConstants_Matrix : public FNiagaraConstantBase +struct FNiagaraConstant_Matrix : public FNiagaraConstantBase { GENERATED_USTRUCT_BODY() - FNiagaraConstants_Matrix() + FNiagaraConstant_Matrix() : Value(FMatrix::Identity) {} - FNiagaraConstants_Matrix(FName InName, const FMatrix& InValue) + FNiagaraConstant_Matrix(FName InName, const FMatrix& InValue) : FNiagaraConstantBase(InName) , Value(InValue) {} @@ -129,28 +79,6 @@ struct FNiagaraConstants_Matrix : public FNiagaraConstantBase FMatrix Value; }; -//Dummy struct used to serialize in the old layout of FNiagaraConstants -//This should be removed once everyone has recompiled and saved their scripts. -USTRUCT() -struct FDeprecatedNiagaraConstants -{ - GENERATED_USTRUCT_BODY() - - //DEPRECATED PROPERTIES. REMOVE SOON! - UPROPERTY() - TArray ScalarConstantsInfo_DEPRECATED; - UPROPERTY() - TArray VectorConstantsInfo_DEPRECATED; - UPROPERTY() - TArray MatrixConstantsInfo_DEPRECATED; - UPROPERTY() - TArray ScalarConstants_DEPRECATED; - UPROPERTY() - TArray VectorConstants_DEPRECATED; - UPROPERTY() - TArray MatrixConstants_DEPRECATED; -}; - USTRUCT() struct FNiagaraConstants { @@ -159,11 +87,11 @@ struct FNiagaraConstants public: UPROPERTY(EditAnywhere, EditFixedSize, Category = "Constant") - TArray ScalarConstants; + TArray ScalarConstants; UPROPERTY(EditAnywhere, EditFixedSize, Category = "Constant") - TArray VectorConstants; + TArray VectorConstants; UPROPERTY(EditAnywhere, EditFixedSize, Category = "Constant") - TArray MatrixConstants; + TArray MatrixConstants; NIAGARA_API void Empty(); NIAGARA_API void GetScalarConstant(int32 Index, float& OutValue, FNiagaraVariableInfo& OutInfo); @@ -176,20 +104,15 @@ public: NIAGARA_API void Init(class UNiagaraEmitterProperties* EmitterProps, struct FNiagaraEmitterScriptProperties* ScriptProps); - /** - Copies constants in from the script as usual but allows overrides from old data in an FNiagaraConstantMap. - Only used for BC. DO NOT USE. - */ - NIAGARA_API void InitFromOldMap(FNiagaraConstantMap& OldMap); - /** Fills the entire constants set into the constant table. */ void AppendToConstantsTable(TArray& ConstantsTable)const; /** Fills only selected constants into the table. In the order they appear in the array of passed names not the order they appear in the set. - Checks the passed map for entires to superceed the default values in the set. + Checks the passed map for entries to supersede the default values in the set. */ - void AppendToConstantsTable(TArray& ConstantsTable, const FNiagaraConstantMap& Externals)const; + void AppendToConstantsTable(TArray& ConstantsTable, const FNiagaraConstants& Externals)const; + NIAGARA_API void SetOrAdd(const FNiagaraVariableInfo& Constant, float Value); NIAGARA_API void SetOrAdd(const FNiagaraVariableInfo& Constant, const FVector4& Value); @@ -212,10 +135,15 @@ public: NIAGARA_API FVector4* FindVector(FName Name); NIAGARA_API FMatrix* FindMatrix(FName Name); + NIAGARA_API const float* FindScalar(FName Name) const; + NIAGARA_API const FVector4* FindVector(FName Name) const; + NIAGARA_API const FMatrix* FindMatrix(FName Name) const; + + /** Return the first constant used for this constant in a table. */ FORCEINLINE int32 GetTableIndex_Scalar(const FNiagaraVariableInfo& Constant)const { - int Idx = ScalarConstants.IndexOfByPredicate([&](const FNiagaraConstants_Float& V){ return Constant.Name == V.Name; }); + int Idx = ScalarConstants.IndexOfByPredicate([&](const FNiagaraConstant_Float& V){ return Constant.Name == V.Name; }); if (Idx != INDEX_NONE) { return Idx; @@ -225,7 +153,7 @@ public: FORCEINLINE int32 GetTableIndex_Vector(const FNiagaraVariableInfo& Constant)const { - int Idx = VectorConstants.IndexOfByPredicate([&](const FNiagaraConstants_Vector& V){ return Constant.Name == V.Name; }); + int Idx = VectorConstants.IndexOfByPredicate([&](const FNiagaraConstant_Vector& V){ return Constant.Name == V.Name; }); if (Idx != INDEX_NONE) { return ScalarTableSize() + Idx; @@ -235,11 +163,28 @@ public: FORCEINLINE int32 GetTableIndex_Matrix(const FNiagaraVariableInfo& Constant)const { - int Idx = MatrixConstants.IndexOfByPredicate([&](const FNiagaraConstants_Matrix& V){ return Constant.Name == V.Name; }); + int Idx = MatrixConstants.IndexOfByPredicate([&](const FNiagaraConstant_Matrix& V){ return Constant.Name == V.Name; }); if (Idx != INDEX_NONE) { return ScalarTableSize() + VectorTableSize() + Idx * 4; } return INDEX_NONE; } + + + void Merge(FNiagaraConstants &InConstants) + { + for (FNiagaraConstant_Float& C : InConstants.ScalarConstants) + { + SetOrAdd(FNiagaraVariableInfo(C.Name, ENiagaraDataType::Scalar), C.Value); + } + for (FNiagaraConstant_Vector& C : InConstants.VectorConstants) + { + SetOrAdd(FNiagaraVariableInfo(C.Name, ENiagaraDataType::Vector), C.Value); + } + for (FNiagaraConstant_Matrix& C : InConstants.MatrixConstants) + { + SetOrAdd(FNiagaraVariableInfo(C.Name, ENiagaraDataType::Matrix), C.Value); + } + } }; diff --git a/Engine/Source/Runtime/Niagara/NiagaraScriptConstantData.h b/Engine/Source/Runtime/Niagara/NiagaraScriptConstantData.h index b0c7311add64..56599090d9fe 100644 --- a/Engine/Source/Runtime/Niagara/NiagaraScriptConstantData.h +++ b/Engine/Source/Runtime/Niagara/NiagaraScriptConstantData.h @@ -12,11 +12,6 @@ struct FNiagaraScriptConstantData GENERATED_USTRUCT_BODY() /** The set of external constants for this script. */ - UPROPERTY() - FDeprecatedNiagaraConstants ExternalConstants_DEPRECATED; - UPROPERTY() - FDeprecatedNiagaraConstants InternalConstants_DEPRECATED; - /** Constants driven by the system. Named New for BC reasons. Once all data is updated beyond VER_UE4_NIAGARA_DATA_OBJECT_DEV_UI_FIX. Get rid of the deprecated consts and rename the New. */ UPROPERTY() FNiagaraConstants ExternalConstantsNew; @@ -33,17 +28,18 @@ struct FNiagaraScriptConstantData FNiagaraConstants& GetExternalConstants(){ return ExternalConstantsNew; } - /** Fill a constants table ready for use in an update or spawn. */ - void FillConstantTable(const FNiagaraConstantMap& ExternalConstantsMap, TArray& OutConstantTable) const + void FillConstantTable(const FNiagaraConstants& ExternalConstants, TArray& OutConstantTable) const { //First up in the table comes the External constants in scalar->vector->matrix order. //Only fills the constants actually used by the script. OutConstantTable.Empty(); - ExternalConstantsNew.AppendToConstantsTable(OutConstantTable, ExternalConstantsMap); + ExternalConstantsNew.AppendToConstantsTable(OutConstantTable, ExternalConstants); //Next up add all the internal constants from the script. InternalConstantsNew.AppendToConstantsTable(OutConstantTable); } + + template void SetOrAddInternal(const FNiagaraVariableInfo& Constant, const T& Value) { diff --git a/Engine/Source/Runtime/Niagara/Private/NiagaraCommon.cpp b/Engine/Source/Runtime/Niagara/Private/NiagaraCommon.cpp new file mode 100644 index 000000000000..8a2ebea7f221 --- /dev/null +++ b/Engine/Source/Runtime/Niagara/Private/NiagaraCommon.cpp @@ -0,0 +1,16 @@ +#include "NiagaraPrivate.h" +#include "NiagaraCommon.h" + +uint32 GetNiagaraDataElementCount(ENiagaraDataType Type) +{ + static int32 Counts[] = { 1, 4, 16 }; + return Counts[(uint8)Type]; +} + +uint32 GetNiagaraBytesPerElement(ENiagaraDataType DataType, ENiagaraType Type) +{ + static int32 Sizes[] = { 1, 2, 4, 4 }; + return Sizes[(uint8)Type] * GetNiagaraDataElementCount(DataType); +} + + diff --git a/Engine/Source/Runtime/Niagara/Private/NiagaraConstantSet.cpp b/Engine/Source/Runtime/Niagara/Private/NiagaraConstantSet.cpp index a440a9a8f436..c198541f2f7b 100644 --- a/Engine/Source/Runtime/Niagara/Private/NiagaraConstantSet.cpp +++ b/Engine/Source/Runtime/Niagara/Private/NiagaraConstantSet.cpp @@ -4,123 +4,6 @@ #include "NiagaraConstantSet.h" #include "NiagaraSimulation.h" -////////////////////////////////////////////////////////////////////////// -// FNiagaraConstantMap - -template<> -struct TStructOpsTypeTraits : public TStructOpsTypeTraitsBase -{ - enum - { - WithSerializer = true - }; -}; -IMPLEMENT_STRUCT(NiagaraConstantMap); - -void FNiagaraConstantMap::Empty() -{ - ScalarConstants.Empty(); - VectorConstants.Empty(); - MatrixConstants.Empty(); -} - -void FNiagaraConstantMap::SetOrAdd(FNiagaraVariableInfo ID, float Sc) -{ - check(ID.Type == ENiagaraDataType::Scalar); - ScalarConstants.FindOrAdd(ID) = Sc; -} - -void FNiagaraConstantMap::SetOrAdd(FNiagaraVariableInfo ID, const FVector4& Vc) -{ - check(ID.Type == ENiagaraDataType::Vector); - VectorConstants.FindOrAdd(ID) = Vc; -} - -void FNiagaraConstantMap::SetOrAdd(FNiagaraVariableInfo ID, const FMatrix& Mc) -{ - check(ID.Type == ENiagaraDataType::Matrix); - MatrixConstants.FindOrAdd(ID) = Mc; -} - -void FNiagaraConstantMap::SetOrAdd(FName Name, float Sc) -{ - ScalarConstants.FindOrAdd(FNiagaraVariableInfo(Name, ENiagaraDataType::Scalar)) = Sc; -} - -void FNiagaraConstantMap::SetOrAdd(FName Name, const FVector4& Vc) -{ - VectorConstants.FindOrAdd(FNiagaraVariableInfo(Name, ENiagaraDataType::Vector)) = Vc; -} - -void FNiagaraConstantMap::SetOrAdd(FName Name, const FMatrix& Mc) -{ - MatrixConstants.FindOrAdd(FNiagaraVariableInfo(Name, ENiagaraDataType::Matrix)) = Mc; -} - -float* FNiagaraConstantMap::FindScalar(FNiagaraVariableInfo ID){ return ScalarConstants.Find(ID); } -FVector4* FNiagaraConstantMap::FindVector(FNiagaraVariableInfo ID){ return VectorConstants.Find(ID); } -FMatrix* FNiagaraConstantMap::FindMatrix(FNiagaraVariableInfo ID){ return MatrixConstants.Find(ID); } - -const float* FNiagaraConstantMap::FindScalar(FNiagaraVariableInfo ID)const { return ScalarConstants.Find(ID); } -const FVector4* FNiagaraConstantMap::FindVector(FNiagaraVariableInfo ID)const { return VectorConstants.Find(ID); } -const FMatrix* FNiagaraConstantMap::FindMatrix(FNiagaraVariableInfo ID)const { return MatrixConstants.Find(ID); } - -float* FNiagaraConstantMap::FindScalar(FName Name) { return ScalarConstants.Find(FNiagaraVariableInfo(Name, ENiagaraDataType::Scalar)); } -FVector4* FNiagaraConstantMap::FindVector(FName Name) { return VectorConstants.Find(FNiagaraVariableInfo(Name, ENiagaraDataType::Vector)); } -FMatrix* FNiagaraConstantMap::FindMatrix(FName Name) { return MatrixConstants.Find(FNiagaraVariableInfo(Name, ENiagaraDataType::Matrix)); } - -const float* FNiagaraConstantMap::FindScalar(FName Name)const { return ScalarConstants.Find(FNiagaraVariableInfo(Name, ENiagaraDataType::Scalar)); } -const FVector4* FNiagaraConstantMap::FindVector(FName Name)const { return VectorConstants.Find(FNiagaraVariableInfo(Name, ENiagaraDataType::Vector)); } -const FMatrix* FNiagaraConstantMap::FindMatrix(FName Name)const { return MatrixConstants.Find(FNiagaraVariableInfo(Name, ENiagaraDataType::Matrix)); } - -void FNiagaraConstantMap::Merge(FNiagaraConstants &InConstants) -{ - for (FNiagaraConstants_Float& C : InConstants.ScalarConstants) - { - SetOrAdd(FNiagaraVariableInfo(C.Name, ENiagaraDataType::Scalar), C.Value); - } - for (FNiagaraConstants_Vector& C : InConstants.VectorConstants) - { - SetOrAdd(FNiagaraVariableInfo(C.Name, ENiagaraDataType::Vector), C.Value); - } - for (FNiagaraConstants_Matrix& C : InConstants.MatrixConstants) - { - SetOrAdd(FNiagaraVariableInfo(C.Name, ENiagaraDataType::Matrix), C.Value); - } -} - -void FNiagaraConstantMap::Merge(FNiagaraConstantMap &InMap) -{ - for (auto MapIt = InMap.ScalarConstants.CreateIterator(); MapIt; ++MapIt) - { - SetOrAdd(MapIt.Key(), MapIt.Value()); - } - - for (auto MapIt = InMap.VectorConstants.CreateIterator(); MapIt; ++MapIt) - { - SetOrAdd(MapIt.Key(), MapIt.Value()); - } - - for (auto MapIt = InMap.MatrixConstants.CreateIterator(); MapIt; ++MapIt) - { - SetOrAdd(MapIt.Key(), MapIt.Value()); - } -} - -const TMap &FNiagaraConstantMap::GetScalarConstants() const -{ - return ScalarConstants; -} - -const TMap &FNiagaraConstantMap::GetVectorConstants() const -{ - return VectorConstants; -} - -const TMap &FNiagaraConstantMap::GetMatrixConstants() const -{ - return MatrixConstants; -} ////////////////////////////////////////////////////////////////////////// @@ -157,30 +40,30 @@ void FNiagaraConstants::Init(UNiagaraEmitterProperties* EmitterProps, FNiagaraEm //Copy the script constants, retaining any altered values. const FNiagaraConstants& ScriptConstants = ScriptProps->Script->ConstantData.GetExternalConstants(); - TArray NewScalarConstants = ScriptConstants.ScalarConstants; + TArray NewScalarConstants = ScriptConstants.ScalarConstants; for (auto& Override : ScalarConstants) { - int32 Idx = NewScalarConstants.IndexOfByPredicate([&](const FNiagaraConstants_Float& C){ return Override.Name == C.Name; }); + int32 Idx = NewScalarConstants.IndexOfByPredicate([&](const FNiagaraConstant_Float& C){ return Override.Name == C.Name; }); if (Idx != INDEX_NONE) NewScalarConstants[Idx].Value = Override.Value; } ScalarConstants = NewScalarConstants; - TArray NewVectorConstants = ScriptConstants.VectorConstants; + TArray NewVectorConstants = ScriptConstants.VectorConstants; for (auto& Override : VectorConstants) { - int32 Idx = NewVectorConstants.IndexOfByPredicate([&](const FNiagaraConstants_Vector& C){ return Override.Name == C.Name; }); + int32 Idx = NewVectorConstants.IndexOfByPredicate([&](const FNiagaraConstant_Vector& C){ return Override.Name == C.Name; }); if (Idx != INDEX_NONE) NewVectorConstants[Idx].Value = Override.Value; } VectorConstants = NewVectorConstants; - TArray NewMatrixConstants = ScriptConstants.MatrixConstants; + TArray NewMatrixConstants = ScriptConstants.MatrixConstants; for (auto& Override : MatrixConstants) { - int32 Idx = NewMatrixConstants.IndexOfByPredicate([&](const FNiagaraConstants_Matrix& C){ return Override.Name == C.Name; }); + int32 Idx = NewMatrixConstants.IndexOfByPredicate([&](const FNiagaraConstant_Matrix& C){ return Override.Name == C.Name; }); if (Idx != INDEX_NONE) NewMatrixConstants[Idx].Value = Override.Value; @@ -189,45 +72,21 @@ void FNiagaraConstants::Init(UNiagaraEmitterProperties* EmitterProps, FNiagaraEm MatrixConstants = NewMatrixConstants; } -/** -Copies constants in from the script as usual but allows overrides from old data in an FNiagaraConstantMap. -Only used for BC. DO NOT USE. -*/ -void FNiagaraConstants::InitFromOldMap(FNiagaraConstantMap& OldMap) -{ - const TMap& OldScalarConsts = OldMap.GetScalarConstants(); - const TMap& OldVectorConsts = OldMap.GetVectorConstants(); - const TMap& OldMatrixConsts = OldMap.GetMatrixConstants(); - - for (const TPair Pair : OldScalarConsts) - { - ScalarConstants.Add(FNiagaraConstants_Float(Pair.Key.Name, Pair.Value)); - } - for (const TPair& Pair : OldVectorConsts) - { - VectorConstants.Add(FNiagaraConstants_Vector(Pair.Key.Name, Pair.Value)); - } - for (const TPair& Pair : OldMatrixConsts) - { - MatrixConstants.Add(FNiagaraConstants_Matrix(Pair.Key.Name, Pair.Value)); - } -} - void FNiagaraConstants::AppendToConstantsTable(TArray& ConstantsTable)const { int32 Idx = ConstantsTable.Num(); int32 NewIdx = 0; ConstantsTable.AddUninitialized(ScalarTableSize() + VectorTableSize() + MatrixTableSize()); - for (const FNiagaraConstants_Float& Sc : ScalarConstants) + for (const FNiagaraConstant_Float& Sc : ScalarConstants) { ConstantsTable[Idx++] = FVector4(Sc.Value, Sc.Value, Sc.Value, Sc.Value); } - for (const FNiagaraConstants_Vector& Vc : VectorConstants) + for (const FNiagaraConstant_Vector& Vc : VectorConstants) { ConstantsTable[Idx++] = Vc.Value; } - for (const FNiagaraConstants_Matrix& C : MatrixConstants) + for (const FNiagaraConstant_Matrix& C : MatrixConstants) { const FMatrix& Mc = C.Value; ConstantsTable[Idx] = FVector4(Mc.M[0][0], Mc.M[0][1], Mc.M[0][2], Mc.M[0][3]); @@ -238,7 +97,9 @@ void FNiagaraConstants::AppendToConstantsTable(TArray& ConstantsTable) } } -void FNiagaraConstants::AppendToConstantsTable(TArray& ConstantsTable, const FNiagaraConstantMap& Externals)const + + +void FNiagaraConstants::AppendToConstantsTable(TArray& ConstantsTable, const FNiagaraConstants& Externals)const { int32 Idx = ConstantsTable.Num(); ConstantsTable.AddUninitialized(ScalarTableSize() + VectorTableSize() + MatrixTableSize()); @@ -248,7 +109,7 @@ void FNiagaraConstants::AppendToConstantsTable(TArray& ConstantsTable, float Value = Scalar ? *Scalar : ScalarConstants[i].Value; ConstantsTable[Idx++] = FVector4(Value, Value, Value, Value); } - + for (int32 i = 0; i < VectorConstants.Num(); ++i) { const FVector4* Vector = Externals.FindVector(VectorConstants[i].Name); @@ -266,45 +127,46 @@ void FNiagaraConstants::AppendToConstantsTable(TArray& ConstantsTable, } } + void FNiagaraConstants::SetOrAdd(const FNiagaraVariableInfo& Constant, float Value) { check(Constant.Type == ENiagaraDataType::Scalar); - FNiagaraConstants_Float* Const = ScalarConstants.FindByPredicate([&](const FNiagaraConstants_Float& C){ return Constant.Name == C.Name; }); + FNiagaraConstant_Float* Const = ScalarConstants.FindByPredicate([&](const FNiagaraConstant_Float& C){ return Constant.Name == C.Name; }); if (Const) { Const->Value = Value; } else { - ScalarConstants.Add(FNiagaraConstants_Float(Constant.Name, Value)); + ScalarConstants.Add(FNiagaraConstant_Float(Constant.Name, Value)); } } void FNiagaraConstants::SetOrAdd(const FNiagaraVariableInfo& Constant, const FVector4& Value) { check(Constant.Type == ENiagaraDataType::Vector); - FNiagaraConstants_Vector* Const = VectorConstants.FindByPredicate([&](const FNiagaraConstants_Vector& C){ return Constant.Name == C.Name; }); + FNiagaraConstant_Vector* Const = VectorConstants.FindByPredicate([&](const FNiagaraConstant_Vector& C){ return Constant.Name == C.Name; }); if (Const) { Const->Value = Value; } else { - VectorConstants.Add(FNiagaraConstants_Vector(Constant.Name, Value)); + VectorConstants.Add(FNiagaraConstant_Vector(Constant.Name, Value)); } } void FNiagaraConstants::SetOrAdd(const FNiagaraVariableInfo& Constant, const FMatrix& Value) { check(Constant.Type == ENiagaraDataType::Matrix); - FNiagaraConstants_Matrix* Const = MatrixConstants.FindByPredicate([&](const FNiagaraConstants_Matrix& C){ return Constant.Name == C.Name; }); + FNiagaraConstant_Matrix* Const = MatrixConstants.FindByPredicate([&](const FNiagaraConstant_Matrix& C){ return Constant.Name == C.Name; }); if (Const) { Const->Value = Value; } else { - MatrixConstants.Add(FNiagaraConstants_Matrix(Constant.Name, Value)); + MatrixConstants.Add(FNiagaraConstant_Matrix(Constant.Name, Value)); } } @@ -325,17 +187,38 @@ void FNiagaraConstants::SetOrAdd(FName Name, const FMatrix& Value) float* FNiagaraConstants::FindScalar(FName Name) { - auto* C = ScalarConstants.FindByPredicate([&](const FNiagaraConstants_Float& Constant){ return Constant.Name == Name; }); + auto* C = ScalarConstants.FindByPredicate([&](const FNiagaraConstant_Float& Constant){ return Constant.Name == Name; }); return C ? &C->Value : nullptr; } FVector4* FNiagaraConstants::FindVector(FName Name) { - auto* C = VectorConstants.FindByPredicate([&](const FNiagaraConstants_Vector& Constant){ return Constant.Name == Name; }); + auto* C = VectorConstants.FindByPredicate([&](const FNiagaraConstant_Vector& Constant){ return Constant.Name == Name; }); return C ? &C->Value : nullptr; } FMatrix* FNiagaraConstants::FindMatrix(FName Name) { - auto* C = MatrixConstants.FindByPredicate([&](const FNiagaraConstants_Matrix& Constant){ return Constant.Name == Name; }); + auto* C = MatrixConstants.FindByPredicate([&](const FNiagaraConstant_Matrix& Constant){ return Constant.Name == Name; }); + return C ? &C->Value : nullptr; +} + + + + +const float* FNiagaraConstants::FindScalar(FName Name) const +{ + auto* C = ScalarConstants.FindByPredicate([&](const FNiagaraConstant_Float& Constant) { return Constant.Name == Name; }); + return C ? &C->Value : nullptr; +} + +const FVector4* FNiagaraConstants::FindVector(FName Name) const +{ + auto* C = VectorConstants.FindByPredicate([&](const FNiagaraConstant_Vector& Constant) { return Constant.Name == Name; }); + return C ? &C->Value : nullptr; +} + +const FMatrix* FNiagaraConstants::FindMatrix(FName Name) const +{ + auto* C = MatrixConstants.FindByPredicate([&](const FNiagaraConstant_Matrix& Constant) { return Constant.Name == Name; }); return C ? &C->Value : nullptr; } diff --git a/Engine/Source/Runtime/Niagara/Private/NiagaraEffect.cpp b/Engine/Source/Runtime/Niagara/Private/NiagaraEffect.cpp index eda965177e88..9bbfc276136f 100644 --- a/Engine/Source/Runtime/Niagara/Private/NiagaraEffect.cpp +++ b/Engine/Source/Runtime/Niagara/Private/NiagaraEffect.cpp @@ -46,17 +46,6 @@ void UNiagaraEffect::CreateEffectRendererProps(TSharedPtr Si void UNiagaraEffect::PostLoad() { Super::PostLoad(); - - if (GetLinkerUE4Version() < VER_UE4_NIAGARA_DATA_OBJECT_DEV_UI_FIX) - { - int32 NumEmitters = EmitterPropsSerialized_DEPRECATED.Num(); - for (int32 i = 0; i < NumEmitters; ++i) - { - UNiagaraEmitterProperties* NewProps = NewObject(this); - NewProps->InitFromOldStruct(EmitterPropsSerialized_DEPRECATED[i]); - AddEmitterProperties(NewProps); - } - } } ////////////////////////////////////////////////////////////////////////// @@ -125,7 +114,7 @@ void FNiagaraEffectInstance::Tick(float DeltaSeconds) //TODO - Handle constants better. Like waaaay better. it->GetConstants().Merge(it->GetProperties()->SpawnScriptProps.ExternalConstants); it->GetConstants().Merge(it->GetProperties()->UpdateScriptProps.ExternalConstants); - it->GetConstants().Merge(Constants); + it->GetConstants().Merge(InstanceConstants); it->PreTick(); } diff --git a/Engine/Source/Runtime/Niagara/Private/NiagaraEffectRenderer.cpp b/Engine/Source/Runtime/Niagara/Private/NiagaraEffectRenderer.cpp index e909fc2a7468..2b2bd4d505ef 100644 --- a/Engine/Source/Runtime/Niagara/Private/NiagaraEffectRenderer.cpp +++ b/Engine/Source/Runtime/Niagara/Private/NiagaraEffectRenderer.cpp @@ -166,9 +166,13 @@ void NiagaraEffectRendererSprites::GetDynamicMeshElements(const TArraySubImageInfo.X, Properties->SubImageInfo.Y, 1.0f / Properties->SubImageInfo.X, 1.0f / Properties->SubImageInfo.Y); @@ -180,11 +184,6 @@ void NiagaraEffectRendererSprites::GetDynamicMeshElements(const TArrayVertexData.Num() == 0) + if (!DynamicDataRender || DynamicDataRender->VertexData.Num() == 0) { return; } @@ -542,7 +540,7 @@ FNiagaraDynamicDataBase *NiagaraEffectRendererRibbon::GenerateVertexData(const F TArray& RenderData = DynamicData->VertexData; RenderData.Reset(Data.GetNumInstances() * 2); - //CachedBounds.Init(); + CachedBounds.Init(); // build a sorted list by age, so we always get particles in order // regardless of them being moved around due to dieing and spawning @@ -607,6 +605,9 @@ FNiagaraDynamicDataBase *NiagaraEffectRendererRibbon::GenerateVertexData(const F PrevPos = ParticlePos - ParticleRightRot + ParticleDir; PrevPos2 = ParticlePos + ParticleRightRot + ParticleDir; PrevDir = ParticleDir; + + CachedBounds += ParticlePos + ParticleRightRot; + CachedBounds += ParticlePos - ParticleRightRot; } CPUTimeMS = VertexDataTimer.GetElapsedMilliseconds(); diff --git a/Engine/Source/Runtime/Niagara/Private/NiagaraEmitterProperties.cpp b/Engine/Source/Runtime/Niagara/Private/NiagaraEmitterProperties.cpp index 3238f1aab102..0ffce018ef6d 100644 --- a/Engine/Source/Runtime/Niagara/Private/NiagaraEmitterProperties.cpp +++ b/Engine/Source/Runtime/Niagara/Private/NiagaraEmitterProperties.cpp @@ -100,45 +100,6 @@ void UNiagaraEmitterProperties::Init() UpdateScriptProps.Init(this); } -void UNiagaraEmitterProperties::InitFromOldStruct(FDeprecatedNiagaraEmitterProperties& OldStruct) -{ - EmitterName = OldStruct.Name; - bIsEnabled = OldStruct.bIsEnabled; - SpawnRate = OldStruct.SpawnRate; - UpdateScriptProps.Script = OldStruct.UpdateScript; - SpawnScriptProps.Script = OldStruct.SpawnScript; - Material = OldStruct.Material; - RenderModuleType = OldStruct.RenderModuleType; - StartTime = OldStruct.StartTime; - EndTime = OldStruct.EndTime; - RendererProperties = OldStruct.RendererProperties; - NumLoops = OldStruct.NumLoops; - -#if WITH_EDITORONLY_DATA - //Ensure both scripts are post loaded and compile them so that their constant arrays are correct. - if (SpawnScriptProps.Script) - { - SpawnScriptProps.Script->ConditionalPostLoad(); - if (SpawnScriptProps.Script->Source) - SpawnScriptProps.Script->Source->Compile(); - } - if (UpdateScriptProps.Script) - { - UpdateScriptProps.Script->ConditionalPostLoad(); - if (UpdateScriptProps.Script->Source) - UpdateScriptProps.Script->Source->Compile(); - } -#endif - - UpdateScriptProps.ExternalConstants.InitFromOldMap(OldStruct.ExternalConstants); - SpawnScriptProps.ExternalConstants.InitFromOldMap(OldStruct.ExternalSpawnConstants); - //Also init the spawn constants with the update constants as they used to combined - SpawnScriptProps.ExternalConstants.InitFromOldMap(OldStruct.ExternalConstants); - UpdateScriptProps.ExternalConstants.InitFromOldMap(OldStruct.ExternalSpawnConstants); - - Init(); -} - #if WITH_EDITOR void UNiagaraEmitterProperties::PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent) { diff --git a/Engine/Source/Runtime/Niagara/Private/NiagaraSimulation.cpp b/Engine/Source/Runtime/Niagara/Private/NiagaraSimulation.cpp index 14582dd16ec6..7f7c1e123ca9 100644 --- a/Engine/Source/Runtime/Niagara/Private/NiagaraSimulation.cpp +++ b/Engine/Source/Runtime/Niagara/Private/NiagaraSimulation.cpp @@ -1,6 +1,7 @@ // Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. #include "NiagaraPrivate.h" +#include "NiagaraConstants.h" #include "NiagaraSimulation.h" #include "NiagaraEffectRenderer.h" #include "VectorVM.h" @@ -109,9 +110,13 @@ void FNiagaraSimulation::Init() Data.AddVariables(PinnedProps->UpdateScriptProps.Script->Attributes); Data.AddVariables(PinnedProps->SpawnScriptProps.Script->Attributes); - Constants.Empty(); - Constants.Merge(PinnedProps->UpdateScriptProps.ExternalConstants); - Constants.Merge(PinnedProps->SpawnScriptProps.ExternalConstants); +// ExternalConstantsMap.Empty(); +// ExternalConstantsMap.Merge(PinnedProps->UpdateScriptProps.ExternalConstants); +// ExternalConstantsMap.Merge(PinnedProps->SpawnScriptProps.ExternalConstants); + + ExternalConstants.Empty(); + ExternalConstants.Merge(PinnedProps->UpdateScriptProps.ExternalConstants); + ExternalConstants.Merge(PinnedProps->SpawnScriptProps.ExternalConstants); //Create data storage for event generators. for (FNiagaraEventGeneratorProperties& Generator : Props->SpawnScriptProps.EventGenerators) @@ -231,59 +236,75 @@ int FNiagaraSimulation::GetTotalBytesUsed() return BytesUsed; } + +/** Look for dead particles and move from the end of the list to the dead location, compacting in the process + */ +void FNiagaraSimulation::KillParticles() +{ + SCOPE_CYCLE_COUNTER(STAT_NiagaraKill); + int32 OrigNumParticles = Data.GetNumInstances(); + int32 CurNumParticles = OrigNumParticles; + int32 ParticleIndex = OrigNumParticles - 1; + + if (bGenerateDeathEvents) + { + DeathEventGenerator.BeginTrackingDeaths(); + } + + const FVector4* ParticleRelativeTimes = Data.GetVariableData(FNiagaraVariableInfo(BUILTIN_VAR_PARTICLEAGE, ENiagaraDataType::Vector)); + if (ParticleRelativeTimes) + { + while (ParticleIndex >= 0) + { + if (ParticleRelativeTimes[ParticleIndex].X > 1.0f) + { + if (bGenerateDeathEvents) + { + DeathEventGenerator.OnDeath(ParticleIndex); + } + + check(CurNumParticles > ParticleIndex); + + // Particle is dead, move one from the end here. + MoveParticleToIndex(--CurNumParticles, ParticleIndex); + } + --ParticleIndex; + } + } + + Data.SetNumInstances(CurNumParticles); + + if (bGenerateDeathEvents) + { + DeathEventGenerator.EndTrackingDeaths(); + } + + // check if the emitter has officially died + if (GetTickState() == NTS_Dieing && CurNumParticles == 0) + { + SetTickState(NTS_Dead); + } +} + +/** + * PreTick - handles killing dead particles, emitter death, and buffer swaps + */ void FNiagaraSimulation::PreTick() { UNiagaraEmitterProperties* PinnedProps = Props.Get(); - if (!PinnedProps || !bIsEnabled || TickState == NTS_Suspended || TickState == NTS_Dead) + + if (!PinnedProps || !bIsEnabled + || TickState == NTS_Suspended || TickState == NTS_Dead + || Data.GetNumInstances() == 0) + { return; + } check(Data.GetNumVariables() > 0); check(PinnedProps->SpawnScriptProps.Script); check(PinnedProps->UpdateScriptProps.Script); - // Iterate over looking for dead particles and move from the end of the list to the dead location, compacting in the process - { - SCOPE_CYCLE_COUNTER(STAT_NiagaraKill); - int32 OrigNumParticles = Data.GetNumInstances(); - int32 CurNumParticles = OrigNumParticles; - int32 ParticleIndex = OrigNumParticles-1; - - if (bGenerateDeathEvents) - { - DeathEventGenerator.BeginTrackingDeaths(); - } - const FVector4* ParticleRelativeTimes = Data.GetVariableData(FNiagaraVariableInfo(FName(TEXT("Age")), ENiagaraDataType::Vector)); - if (ParticleRelativeTimes) - { - while (ParticleIndex >= 0) - { - if (ParticleRelativeTimes[ParticleIndex].X > 1.0f) - { - if (bGenerateDeathEvents) - { - DeathEventGenerator.OnDeath(ParticleIndex); - } - - check(CurNumParticles > ParticleIndex); - // Particle is dead, move one from the end here. - MoveParticleToIndex(--CurNumParticles, ParticleIndex); - } - --ParticleIndex; - } - } - Data.SetNumInstances(CurNumParticles); - - if (bGenerateDeathEvents) - { - DeathEventGenerator.EndTrackingDeaths(); - } - - // check if the emitter has officially died - if (GetTickState() == NTS_Dieing && CurNumParticles == 0) - { - SetTickState(NTS_Dead); - } - } + KillParticles(); //Swap all data set buffers before doing the main tick on any simulation. for (TPair SetPair : DataSetMap) @@ -295,46 +316,36 @@ void FNiagaraSimulation::PreTick() void FNiagaraSimulation::Tick(float DeltaSeconds) { SCOPE_CYCLE_COUNTER(STAT_NiagaraTick); + SimpleTimer TickTime; UNiagaraEmitterProperties* PinnedProps = Props.Get(); - if (!PinnedProps || !bIsEnabled || TickState==NTS_Suspended || TickState==NTS_Dead) + if (!PinnedProps || !bIsEnabled || TickState == NTS_Suspended || TickState == NTS_Dead) + { return; + } - SimpleTimer TickTime; + Age += DeltaSeconds; check(Data.GetNumVariables() > 0); check(PinnedProps->SpawnScriptProps.Script); check(PinnedProps->UpdateScriptProps.Script); - //Handle Event Actions. - auto CallEventActions = [&](FNiagaraEventReceiverProperties& Receiver) - { - for (auto& Action : Receiver.EmitterActions) - { - if (Action) - Action->PerformAction(*this, Receiver); - } - }; - for (auto& Receiver : Props->SpawnScriptProps.EventReceivers) { CallEventActions(Receiver); } - for (auto& Receiver : Props->UpdateScriptProps.EventReceivers) { CallEventActions(Receiver); } - - int32 OrigNumParticles = Data.GetNumInstances(); - int32 NumToSpawn = 0; + TickEvents(DeltaSeconds); // Figure out how many we will spawn. - NumToSpawn = CalcNumToSpawn(DeltaSeconds); + int32 OrigNumParticles = Data.GetNumInstances(); + int32 NumToSpawn = CalcNumToSpawn(DeltaSeconds); int32 MaxNewParticles = OrigNumParticles + NumToSpawn; Data.Allocate(MaxNewParticles); - Age += DeltaSeconds; - Constants.SetOrAdd(TEXT("Emitter Age"), FVector4(Age, Age, Age, Age)); - Constants.SetOrAdd(TEXT("Delta Time"), FVector4(DeltaSeconds, DeltaSeconds, DeltaSeconds, DeltaSeconds)); + ExternalConstants.SetOrAdd(BUILTIN_CONST_EMITTERAGE, FVector4(Age, Age, Age, Age)); + ExternalConstants.SetOrAdd(BUILTIN_CONST_DELTATIME, FVector4(DeltaSeconds, DeltaSeconds, DeltaSeconds, DeltaSeconds)); // Simulate particles forward by DeltaSeconds. if (TickState==NTS_Running || TickState==NTS_Dieing) { SCOPE_CYCLE_COUNTER(STAT_NiagaraSimulate); - RunVMScript(PinnedProps->UpdateScriptProps, EUnusedAttributeBehaviour::Copy); + RunVMScript(PinnedProps->UpdateScriptProps, EUnusedAttributeBehaviour::PassThrough); } //Init new particles with the spawn script. @@ -344,20 +355,39 @@ void FNiagaraSimulation::Tick(float DeltaSeconds) Data.SetNumInstances(MaxNewParticles); //For now, zero any unused attributes here. But as this is really uninitialized data we should maybe make this a more serious error. RunVMScript(PinnedProps->SpawnScriptProps, EUnusedAttributeBehaviour::Zero, OrigNumParticles, NumToSpawn); - } - if (bGenerateSpawnEvents) - { - SpawnEventGenerator.OnSpawned(OrigNumParticles, NumToSpawn); + if (bGenerateSpawnEvents) + { + SpawnEventGenerator.OnSpawned(OrigNumParticles, NumToSpawn); + } } CPUTimeMS = TickTime.GetElapsedMilliseconds(); INC_DWORD_STAT_BY(STAT_NiagaraNumParticles, Data.GetNumInstances()); - } + +void FNiagaraSimulation::TickEvents(float DeltaSeconds) +{ + //Handle Event Actions. + auto CallEventActions = [&](FNiagaraEventReceiverProperties& Receiver) + { + for (auto& Action : Receiver.EmitterActions) + { + if (Action) + { + Action->PerformAction(*this, Receiver); + } + } + }; + + for (auto& Receiver : Props->SpawnScriptProps.EventReceivers) { CallEventActions(Receiver); } + for (auto& Receiver : Props->UpdateScriptProps.EventReceivers) { CallEventActions(Receiver); } +} + + void FNiagaraSimulation::RunVMScript(FNiagaraEmitterScriptProperties& ScriptProps, EUnusedAttributeBehaviour UnusedAttribBehaviour) { RunVMScript(ScriptProps, UnusedAttribBehaviour, 0, Data.GetNumInstances()); @@ -371,7 +401,9 @@ void FNiagaraSimulation::RunVMScript(FNiagaraEmitterScriptProperties& ScriptProp void FNiagaraSimulation::RunVMScript(FNiagaraEmitterScriptProperties& ScriptProps, EUnusedAttributeBehaviour UnusedAttribBehaviour, uint32 StartParticle, uint32 NumParticles) { if (NumParticles == 0) + { return; + } UNiagaraScript* Script = ScriptProps.Script; @@ -384,18 +416,11 @@ void FNiagaraSimulation::RunVMScript(FNiagaraEmitterScriptProperties& ScriptProp check(StartParticle + NumParticles <= CurrNumParticles); - const FVector4* InputBuffer = Data.GetPreviousBuffer(); - const FVector4* OutputBuffer = Data.GetCurrentBuffer(); - - uint32 InputAttributeStride = Data.GetPrevDataAllocation(); - uint32 OutputAttributeStride = Data.GetDataAllocation(); - VectorRegister* InputRegisters[VectorVM::MaxInputRegisters] = { 0 }; VectorRegister* OutputRegisters[VectorVM::MaxOutputRegisters] = { 0 }; //The current script run will be using NumScriptAttrs. We must pick out the Attributes form the simulation data in the order that they appear in the script. //The remaining attributes being handled according to UnusedAttribBehaviour - const int32 NumSimulationAttrs = Data.GetNumVariables(); const int32 NumScriptAttrs = Script->Attributes.Num(); check(NumScriptAttrs < VectorVM::MaxInputRegisters); @@ -403,55 +428,65 @@ void FNiagaraSimulation::RunVMScript(FNiagaraEmitterScriptProperties& ScriptProp int32 NumInputRegisters = 0; int32 NumOutputRegitsers = 0; - // Setup input and output registers. - for (TPair AttrIndexPair : Data.GetVariables()) + { - const FNiagaraVariableInfo& AttrInfo = AttrIndexPair.Key; + SCOPE_CYCLE_COUNTER(STAT_NiagaraSimRegisterSetup); - FVector4* InBuff; - FVector4* OutBuff; - Data.GetVariableData(AttrInfo, InBuff, OutBuff, StartParticle); - - int32 AttrIndex = Script->Attributes.Find(AttrInfo); - if (AttrIndex != INDEX_NONE) + // Setup input and output registers. + for (TPair AttrIndexPair : Data.GetVariables()) { - //The input buffer can be NULL but only if this script never accesses it. - check(InBuff || !Script->Usage.bReadsAttriubteData); + const FNiagaraVariableInfo& AttrInfo = AttrIndexPair.Key; - //This attribute is used in this script so set it to the correct Input and Output buffer locations. - InputRegisters[AttrIndex] = (VectorRegister*)InBuff; - OutputRegisters[AttrIndex] = (VectorRegister*)OutBuff; - - NumInputRegisters += InBuff ? 1 : 0; - NumOutputRegitsers += OutBuff ? 1 : 0; - } - else - { - //This attribute is not used in this script so handle it accordingly. - check(OutBuff); + FVector4* InBuff; + FVector4* OutBuff; + Data.GetVariableData(AttrInfo, InBuff, OutBuff, StartParticle); - if (UnusedAttribBehaviour == EUnusedAttributeBehaviour::Copy) + int32 AttrIndex = Script->Attributes.Find(AttrInfo); + if (AttrIndex != INDEX_NONE) { - check(InBuff); - FMemory::Memcpy(OutBuff, InBuff, NumParticles * sizeof(FVector4)); + //The input buffer can be NULL but only if this script never accesses it. + check(InBuff || !Script->Usage.bReadsAttriubteData); + + //This attribute is used in this script so set it to the correct Input and Output buffer locations. + InputRegisters[AttrIndex] = (VectorRegister*)InBuff; + OutputRegisters[AttrIndex] = (VectorRegister*)OutBuff; + + NumInputRegisters += InBuff ? 1 : 0; + NumOutputRegitsers += OutBuff ? 1 : 0; } - else if (UnusedAttribBehaviour == EUnusedAttributeBehaviour::Zero) + else { - FMemory::Memzero(OutBuff, NumParticles * sizeof(FVector4)); - } - else if (UnusedAttribBehaviour == EUnusedAttributeBehaviour::MarkInvalid) - { - FMemory::Memset(OutBuff, NIAGARA_INVALID_MEMORY, NumParticles * sizeof(FVector4)); + //This attribute is not used in this script so handle it accordingly. + check(OutBuff); + + if (UnusedAttribBehaviour == EUnusedAttributeBehaviour::PassThrough) + { + Data.GetVariableBuffer(AttrInfo).EnablePassThrough(); + } + else if (UnusedAttribBehaviour == EUnusedAttributeBehaviour::Copy) + { + check(InBuff); + FMemory::Memcpy(OutBuff, InBuff, NumParticles * sizeof(FVector4)); + } + else if (UnusedAttribBehaviour == EUnusedAttributeBehaviour::Zero) + { + FMemory::Memzero(OutBuff, NumParticles * sizeof(FVector4)); + } + else if (UnusedAttribBehaviour == EUnusedAttributeBehaviour::MarkInvalid) + { + FMemory::Memset(OutBuff, NIAGARA_INVALID_MEMORY, NumParticles * sizeof(FVector4)); + } } } } - //Fill constant table with required emitter constants and internal script constants. + // Fill constant table with required emitter constants and internal script constants. TArray ConstantTable; - Script->ConstantData.FillConstantTable(Constants, ConstantTable); + //Script->ConstantData.FillConstantTable(ExternalConstantsMap, ConstantTable); + Script->ConstantData.FillConstantTable(ExternalConstants, ConstantTable); - //Fill in the shared data table + // Fill in the shared data table TArray> SharedDataTable; for (FNiagaraEventReceiverProperties Receiver : ScriptProps.EventReceivers) diff --git a/Engine/Source/Runtime/Niagara/Public/NiagaraCommon.h b/Engine/Source/Runtime/Niagara/Public/NiagaraCommon.h index 0d51b3a94929..a1ab6d7a0672 100644 --- a/Engine/Source/Runtime/Niagara/Public/NiagaraCommon.h +++ b/Engine/Source/Runtime/Niagara/Public/NiagaraCommon.h @@ -15,6 +15,19 @@ enum class ENiagaraDataType : uint8 }; +enum class ENiagaraType : uint8 +{ + Byte, + Word, + DWord, + Float +}; + +enum ENiagaraSimTarget +{ + CPUSim, + GPUComputeSim +}; enum ENiagaraTickState @@ -26,6 +39,11 @@ enum ENiagaraTickState }; +uint32 GetNiagaraDataElementCount(ENiagaraDataType Type); +uint32 GetNiagaraBytesPerElement(ENiagaraDataType DataType, ENiagaraType Type); + + + USTRUCT() struct FNiagaraVariableInfo { diff --git a/Engine/Source/Runtime/Niagara/Public/NiagaraFunctionLibrary.h b/Engine/Source/Runtime/Niagara/Public/NiagaraFunctionLibrary.h index 616eacbd99b0..969c6847d510 100644 --- a/Engine/Source/Runtime/Niagara/Public/NiagaraFunctionLibrary.h +++ b/Engine/Source/Runtime/Niagara/Public/NiagaraFunctionLibrary.h @@ -7,7 +7,7 @@ /** -* A C++ and Blueprint accessible library of utility functions for accessing Leap Motion device. +* A C++ and Blueprint accessible library of utility functions for accessing Niagara simulations * All positions & orientations are returned in Unreal reference frame & units, assuming the Leap device is located at the origin. */ UCLASS() diff --git a/Engine/Source/Runtime/OpenGLDrv/Private/OpenGLCommands.cpp b/Engine/Source/Runtime/OpenGLDrv/Private/OpenGLCommands.cpp index b490e87dae58..a4b034373e67 100644 --- a/Engine/Source/Runtime/OpenGLDrv/Private/OpenGLCommands.cpp +++ b/Engine/Source/Runtime/OpenGLDrv/Private/OpenGLCommands.cpp @@ -1837,10 +1837,15 @@ void FOpenGLDynamicRHI::RHISetRenderTargets( void FOpenGLDynamicRHI::RHIDiscardRenderTargets(bool Depth, bool Stencil, uint32 ColorBitMask) { - if(FOpenGL::SupportsDiscardFrameBuffer()) + if (FOpenGL::SupportsDiscardFrameBuffer()) { + { + QUICK_SCOPE_CYCLE_COUNTER(STAT_RHIMETHOD_DiscardRenderTargets_Flush); + FRHICommandListExecutor::GetImmediateCommandList().ImmediateFlush(EImmediateFlushType::FlushRHIThread); + } + // 8 Color + Depth + Stencil = 10 - GLenum Attachments[10]; + GLenum Attachments[MaxSimultaneousRenderTargets + 2]; uint32 I=0; if(Depth) { @@ -1853,7 +1858,7 @@ void FOpenGLDynamicRHI::RHIDiscardRenderTargets(bool Depth, bool Stencil, uint32 I++; } - ColorBitMask &= (1 << 8) - 1; + ColorBitMask &= (1 << MaxSimultaneousRenderTargets) - 1; uint32 J = 0; while (ColorBitMask) { diff --git a/Engine/Source/Runtime/OpenGLDrv/Private/OpenGLDevice.cpp b/Engine/Source/Runtime/OpenGLDrv/Private/OpenGLDevice.cpp index 5004162fae19..3cbe05f36902 100644 --- a/Engine/Source/Runtime/OpenGLDrv/Private/OpenGLDevice.cpp +++ b/Engine/Source/Runtime/OpenGLDrv/Private/OpenGLDevice.cpp @@ -851,6 +851,7 @@ static void InitRHICapabilitiesForGL() SetupTextureFormat( PF_R32_SINT, FOpenGLTextureFormat( GL_R32I, GL_NONE, GL_RED_INTEGER, GL_INT, false, false)); SetupTextureFormat( PF_R16_UINT, FOpenGLTextureFormat( GL_R16UI, GL_NONE, GL_RED_INTEGER, GL_UNSIGNED_SHORT, false, false)); SetupTextureFormat( PF_R16_SINT, FOpenGLTextureFormat( GL_R16I, GL_NONE, GL_RED_INTEGER, GL_SHORT, false, false)); + SetupTextureFormat( PF_R8_UINT, FOpenGLTextureFormat( GL_R8UI, GL_NONE, GL_RED_INTEGER, GL_UNSIGNED_BYTE, false, false)); SetupTextureFormat( PF_FloatRGBA, FOpenGLTextureFormat( GL_RGBA16F, GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT, false, false)); if (FOpenGL::GetShaderPlatform() == EShaderPlatform::SP_OPENGL_ES31_EXT) { diff --git a/Engine/Source/Runtime/OpenGLDrv/Private/OpenGLShaders.cpp b/Engine/Source/Runtime/OpenGLDrv/Private/OpenGLShaders.cpp index cf74d9c5ac1e..9ce189804325 100644 --- a/Engine/Source/Runtime/OpenGLDrv/Private/OpenGLShaders.cpp +++ b/Engine/Source/Runtime/OpenGLDrv/Private/OpenGLShaders.cpp @@ -9,6 +9,7 @@ #include "Shader.h" #include "GlobalShader.h" #include "ShaderCache.h" +#include "CrossCompilerCommon.h" #define CHECK_FOR_GL_SHADERS_TO_REPLACE 0 @@ -1204,9 +1205,8 @@ void FOpenGLLinkedProgram::VerifyUniformBlockBindings( int Stage, uint32 FirstUn { if ( FOpenGL::SupportsSeparateShaderObjects() && FOpenGL::SupportsUniformBuffers() ) { - static const ANSICHAR StagePrefix[CrossCompiler::NUM_SHADER_STAGES] = { 'v', 'p', 'g', 'h', 'd', 'c'}; FOpenGLUniformName Name; - Name.Buffer[0] = StagePrefix[Stage]; + Name.Buffer[0] = CrossCompiler::ShaderStageIndexToTypeName(Stage); Name.Buffer[1] = 'b'; GLuint StageProgram = Config.Shaders[Stage].Resource; @@ -1225,7 +1225,6 @@ void FOpenGLLinkedProgram::VerifyUniformBlockBindings( int Stage, uint32 FirstUn void FOpenGLLinkedProgram::ConfigureShaderStage( int Stage, uint32 FirstUniformBuffer ) { - static const ANSICHAR StagePrefix[CrossCompiler::NUM_SHADER_STAGES] = { 'v', 'p', 'g', 'h', 'd', 'c'}; static const GLint FirstTextureUnit[CrossCompiler::NUM_SHADER_STAGES] = { FOpenGL::GetFirstVertexTextureUnit(), @@ -1252,7 +1251,7 @@ void FOpenGLLinkedProgram::ConfigureShaderStage( int Stage, uint32 FirstUniformB VERIFY_GL_SCOPE(); FOpenGLUniformName Name; - Name.Buffer[0] = StagePrefix[Stage]; + Name.Buffer[0] = CrossCompiler::ShaderStageIndexToTypeName(Stage); GLuint StageProgram = FOpenGL::SupportsSeparateShaderObjects() ? Config.Shaders[Stage].Resource : Program; diff --git a/Engine/Source/Runtime/OpenGLDrv/Private/Windows/OpenGLWindows.cpp b/Engine/Source/Runtime/OpenGLDrv/Private/Windows/OpenGLWindows.cpp index bb7883d3af66..42b0bb6d40f1 100644 --- a/Engine/Source/Runtime/OpenGLDrv/Private/Windows/OpenGLWindows.cpp +++ b/Engine/Source/Runtime/OpenGLDrv/Private/Windows/OpenGLWindows.cpp @@ -82,6 +82,11 @@ public: } } + bool ContextWasAlreadyActive() const + { + return bSameDCAndContext; + } + private: HDC PrevDC; HGLRC PrevContext; @@ -182,8 +187,13 @@ static void PlatformCreateDummyGLWindow(FPlatformOpenGLContext* OutContext) static bool PlatformOpenGL3() { // OpenGL3 is our default platform for Windows XP - return FWindowsPlatformMisc::VerifyWindowsVersion(6, 0) == false || FParse::Param(FCommandLine::Get(),TEXT("opengl")) || FParse::Param(FCommandLine::Get(),TEXT("opengl3")); +#if (WINVER < 0x0600) + return true; +#else + return FParse::Param(FCommandLine::Get(),TEXT("opengl")) || FParse::Param(FCommandLine::Get(),TEXT("opengl3")); +#endif } + static bool PlatformOpenGL4() { return FParse::Param(FCommandLine::Get(),TEXT("opengl4")); @@ -382,11 +392,15 @@ void PlatformReleaseOpenGLContext(FPlatformOpenGLDevice* Device, FPlatformOpenGL Device->ViewportContexts.RemoveSingle(Context); Device->TargetDirty = true; + bool bActiveContextWillBeReleased = false; + { FScopeLock ScopeLock(Device->ContextUsageGuard); { FScopeContext ScopeContext(Context); + bActiveContextWillBeReleased = ScopeContext.ContextWasAlreadyActive(); + DeleteQueriesForCurrentContext(Context->OpenGLContext); glBindVertexArray(0); glDeleteVertexArrays(1, &Context->VertexArrayObject); @@ -404,7 +418,7 @@ void PlatformReleaseOpenGLContext(FPlatformOpenGLDevice* Device, FPlatformOpenGL check(Context->DeviceContext); - if (wglGetCurrentDC() == Context->DeviceContext) + if (bActiveContextWillBeReleased) { wglMakeCurrent( NULL, NULL ); } diff --git a/Engine/Source/Runtime/RHI/Private/RHI.cpp b/Engine/Source/Runtime/RHI/Private/RHI.cpp index acd3e46503da..8a496449da51 100644 --- a/Engine/Source/Runtime/RHI/Private/RHI.cpp +++ b/Engine/Source/Runtime/RHI/Private/RHI.cpp @@ -283,6 +283,7 @@ bool GRHISupportsRHIThread = false; bool GRHISupportsParallelRHIExecute = false; bool GSupportsHDR32bppEncodeModeIntrinsic = false; bool GSupportsParallelOcclusionQueries = false; +bool GSupportsRenderTargetWriteMask = false; bool GRHISupportsMSAADepthSampleAccess = false; diff --git a/Engine/Source/Runtime/RHI/Public/DynamicRHI.h b/Engine/Source/Runtime/RHI/Public/DynamicRHI.h index 57672f125955..058570db8fd0 100644 --- a/Engine/Source/Runtime/RHI/Public/DynamicRHI.h +++ b/Engine/Source/Runtime/RHI/Public/DynamicRHI.h @@ -686,6 +686,15 @@ public: // FlushType: Wait RHI Thread virtual FTexture2DRHIRef RHICreateTexture2D(uint32 SizeX, uint32 SizeY, uint8 Format, uint32 NumMips, uint32 NumSamples, uint32 Flags, FRHIResourceCreateInfo& CreateInfo) = 0; + /** + * Creates an FStructuredBuffer for the RT write mask of a render target + * @param RenderTarget - the RT to create the buffer for + */ + virtual FStructuredBufferRHIRef RHICreateRTWriteMaskBuffer(FTexture2DRHIParamRef RenderTarget) + { + return nullptr; + } + /** * Thread-safe function that can be used to create a texture outside of the * rendering thread. This function can ONLY be called if GRHISupportsAsyncTextureCreation @@ -1022,7 +1031,7 @@ public: // FlushType: Flush Immediate (seems wrong) virtual void RHISetStreamOutTargets(uint32 NumTargets, const FVertexBufferRHIParamRef* VertexBuffers, const uint32* Offsets) = 0; - // FlushType: Flush Immediate (seems wrong) + // Each RHI should flush if it needs to when implementing this method. virtual void RHIDiscardRenderTargets(bool Depth, bool Stencil, uint32 ColorBitMask) = 0; // Blocks the CPU until the GPU catches up and goes idle. diff --git a/Engine/Source/Runtime/RHI/Public/RHI.h b/Engine/Source/Runtime/RHI/Public/RHI.h index 1e8ca49638d8..d33e44b66552 100644 --- a/Engine/Source/Runtime/RHI/Public/RHI.h +++ b/Engine/Source/Runtime/RHI/Public/RHI.h @@ -138,6 +138,9 @@ extern RHI_API bool GSupportsWideMRT; /** True if the RHI and current hardware supports supports depth bounds testing */ extern RHI_API bool GSupportsDepthBoundsTest; +/** True if the RHI and current hardware support a render target write mask */ +extern RHI_API bool GSupportsRenderTargetWriteMask; + /** True if the RHI and current hardware supports efficient AsyncCompute (by default we assume false and later we can enable this for more hardware) */ extern RHI_API bool GSupportsEfficientAsyncCompute; @@ -1006,6 +1009,7 @@ enum class EResourceTransitionAccess ERWBarrier, // Mostly for UAVs. Transition to read/write state and always insert a resource barrier. ERWNoBarrier, //Mostly UAVs. Indicates we want R/W access and do not require synchronization for the duration of the RW state. The initial transition from writable->RWNoBarrier and readable->RWNoBarrier still requires a sync ERWSubResBarrier, //For special cases where read/write happens to different subresources of the same resource in the same call. Inserts a barrier, but read validation will pass. Temporary until we pass full subresource info to all transition calls. + EMetaData, // For transitioning texture meta data, for example for making readable in shaders EMaxAccess, }; diff --git a/Engine/Source/Runtime/RHI/Public/RHICommandList.h b/Engine/Source/Runtime/RHI/Public/RHICommandList.h index 3801fc9bcaff..80e95c15444f 100644 --- a/Engine/Source/Runtime/RHI/Public/RHICommandList.h +++ b/Engine/Source/Runtime/RHI/Public/RHICommandList.h @@ -2552,7 +2552,12 @@ public: { return GDynamicRHI->RHICreateTexture2D_RenderThread(*this, SizeX, SizeY, Format, NumMips, NumSamples, Flags, CreateInfo); } - + + FORCEINLINE FStructuredBufferRHIRef CreateRTWriteMaskBuffer(FTexture2DRHIRef RenderTarget) + { + return GDynamicRHI->RHICreateRTWriteMaskBuffer(RenderTarget); + } + FORCEINLINE FTexture2DRHIRef AsyncCreateTexture2D(uint32 SizeX, uint32 SizeY, uint8 Format, uint32 NumMips, uint32 Flags, void** InitialMipData, uint32 NumInitialMips) { return GDynamicRHI->RHIAsyncCreateTexture2D(SizeX, SizeY, Format, NumMips, Flags, InitialMipData, NumInitialMips); @@ -2818,8 +2823,6 @@ public: FORCEINLINE void DiscardRenderTargets(bool Depth,bool Stencil,uint32 ColorBitMask) { - QUICK_SCOPE_CYCLE_COUNTER(STAT_RHIMETHOD_DiscardRenderTargets_Flush); - ImmediateFlush(EImmediateFlushType::FlushRHIThread); GDynamicRHI->RHIDiscardRenderTargets(Depth,Stencil,ColorBitMask); } @@ -3184,6 +3187,11 @@ FORCEINLINE FTexture2DRHIRef RHICreateTexture2D(uint32 SizeX, uint32 SizeY, uint return FRHICommandListExecutor::GetImmediateCommandList().CreateTexture2D(SizeX, SizeY, Format, NumMips, NumSamples, Flags, CreateInfo); } +FORCEINLINE FStructuredBufferRHIRef RHICreateRTWriteMaskBuffer(FTexture2DRHIRef RenderTarget) +{ + return FRHICommandListExecutor::GetImmediateCommandList().CreateRTWriteMaskBuffer(RenderTarget); +} + FORCEINLINE FTexture2DRHIRef RHIAsyncCreateTexture2D(uint32 SizeX, uint32 SizeY, uint8 Format, uint32 NumMips, uint32 Flags, void** InitialMipData, uint32 NumInitialMips) { return FRHICommandListExecutor::GetImmediateCommandList().AsyncCreateTexture2D(SizeX, SizeY, Format, NumMips, Flags, InitialMipData, NumInitialMips); diff --git a/Engine/Source/Runtime/RHI/Public/RHIDefinitions.h b/Engine/Source/Runtime/RHI/Public/RHIDefinitions.h index e31f5f101744..08cb4119194e 100644 --- a/Engine/Source/Runtime/RHI/Public/RHIDefinitions.h +++ b/Engine/Source/Runtime/RHI/Public/RHIDefinitions.h @@ -542,6 +542,8 @@ enum ETextureCreateFlags TexCreate_NoFastClear = 1 << 25, // Texture is a depth stencil resolve target TexCreate_DepthStencilResolveTarget = 1 << 26, + // Render target will not FinalizeFastClear; Caches and meta data will be flushed, but clearing will be skipped (avoids potentially trashing metadata) + TexCreate_NoFastClearFinalize = 1 << 28, }; enum EAsyncComputePriority diff --git a/Engine/Source/Runtime/RenderCore/Private/RenderUtils.cpp b/Engine/Source/Runtime/RenderCore/Private/RenderUtils.cpp index e943c9de0c46..92366714d8e9 100644 --- a/Engine/Source/Runtime/RenderCore/Private/RenderUtils.cpp +++ b/Engine/Source/Runtime/RenderCore/Private/RenderUtils.cpp @@ -124,6 +124,7 @@ FPixelFormatInfo GPixelFormats[PF_MAX] = { TEXT("BC6H"), 4, 4, 1, 16, 3, 0, 1, PF_BC6H }, { TEXT("BC7"), 4, 4, 1, 16, 4, 0, 1, PF_BC7 }, + { TEXT("R8_UINT"), 1, 1, 1, 1, 1, 0, 1, PF_R8_UINT }, }; static struct FValidatePixelFormats diff --git a/Engine/Source/Runtime/Renderer/Private/AtmosphereRendering.cpp b/Engine/Source/Runtime/Renderer/Private/AtmosphereRendering.cpp index 5dceeaf630da..95bac0851b64 100644 --- a/Engine/Source/Runtime/Renderer/Private/AtmosphereRendering.cpp +++ b/Engine/Source/Runtime/Renderer/Private/AtmosphereRendering.cpp @@ -13,6 +13,8 @@ #include "ShowFlags.h" #include "SceneUtils.h" +DECLARE_FLOAT_COUNTER_STAT(TEXT("Atmosphere"), Stat_GPU_Atmosphere, STATGROUP_GPU); + class FAtmosphereShaderPrecomputeTextureParameters { public: @@ -409,6 +411,7 @@ void FDeferredShadingSceneRenderer::RenderAtmosphere(FRHICommandListImmediate& R const FViewInfo& View = Views[ViewIndex]; SCOPED_DRAW_EVENTF(RHICmdList, Atmosphere, TEXT("Atmosphere %dx%d"), View.ViewRect.Width(), View.ViewRect.Height()); + SCOPED_GPU_STAT(RHICmdList, Stat_GPU_Atmosphere); // Set the device viewport for the view. RHICmdList.SetViewport(View.ViewRect.Min.X, View.ViewRect.Min.Y, 0.0f, View.ViewRect.Max.X, View.ViewRect.Max.Y, 1.0f); diff --git a/Engine/Source/Runtime/Renderer/Private/BasePassRendering.cpp b/Engine/Source/Runtime/Renderer/Private/BasePassRendering.cpp index 927de5f56b10..3e14f29472cf 100644 --- a/Engine/Source/Runtime/Renderer/Private/BasePassRendering.cpp +++ b/Engine/Source/Runtime/Renderer/Private/BasePassRendering.cpp @@ -123,6 +123,8 @@ IMPLEMENT_BASEPASS_LIGHTMAPPED_SHADER_TYPE( TUniformLightMapPolicy, TLightMapPolicyHQ ); IMPLEMENT_BASEPASS_LIGHTMAPPED_SHADER_TYPE( TUniformLightMapPolicy, TDistanceFieldShadowsAndLightMapPolicyHQ ); +DECLARE_FLOAT_COUNTER_STAT(TEXT("Basepass"), Stat_GPU_Basepass, STATGROUP_GPU); + void FSkyLightReflectionParameters::GetSkyParametersFromScene( const FScene* Scene, bool bApplySkyLight, @@ -729,6 +731,7 @@ bool FDeferredShadingSceneRenderer::RenderBasePass(FRHICommandListImmediate& RHI { SCOPED_DRAW_EVENT(RHICmdList, BasePass); SCOPE_CYCLE_COUNTER(STAT_BasePassDrawTime); + SCOPED_GPU_STAT(RHICmdList, Stat_GPU_Basepass ); if (GRHICommandList.UseParallelAlgorithms() && CVarParallelBasePass.GetValueOnRenderThread()) { diff --git a/Engine/Source/Runtime/Renderer/Private/BasePassRendering.h b/Engine/Source/Runtime/Renderer/Private/BasePassRendering.h index 08f7ef3d0d0f..f52d58b7142d 100644 --- a/Engine/Source/Runtime/Renderer/Private/BasePassRendering.h +++ b/Engine/Source/Runtime/Renderer/Private/BasePassRendering.h @@ -996,6 +996,10 @@ public: // Modulate with the existing scene color, preserve destination alpha. RHICmdList.SetBlendState( TStaticBlendState::GetRHI()); break; + case BLEND_AlphaComposite: + // Blend with existing scene color. New color is already pre-multiplied by alpha. + RHICmdList.SetBlendState(TStaticBlendState::GetRHI()); + break; }; } } diff --git a/Engine/Source/Runtime/Renderer/Private/CapsuleShadowRendering.cpp b/Engine/Source/Runtime/Renderer/Private/CapsuleShadowRendering.cpp index 83aa8bd75c85..910d1c3bf75b 100644 --- a/Engine/Source/Runtime/Renderer/Private/CapsuleShadowRendering.cpp +++ b/Engine/Source/Runtime/Renderer/Private/CapsuleShadowRendering.cpp @@ -15,6 +15,8 @@ #include "DistanceFieldSurfaceCacheLighting.h" #include "DistanceFieldLightingPost.h" +DECLARE_FLOAT_COUNTER_STAT(TEXT("Capsule Shadows"), Stat_GPU_CapsuleShadows, STATGROUP_GPU); + int32 GCapsuleShadows = 1; FAutoConsoleVariableRef CVarCapsuleShadows( TEXT("r.CapsuleShadows"), @@ -645,6 +647,7 @@ bool FDeferredShadingSceneRenderer::RenderCapsuleDirectShadows( { const FViewInfo& View = Views[ViewIndex]; SCOPED_DRAW_EVENT(RHICmdList, CapsuleShadows); + SCOPED_GPU_STAT(RHICmdList, Stat_GPU_CapsuleShadows); static TArray CapsuleShapeData; CapsuleShapeData.Reset(); @@ -1059,6 +1062,7 @@ void FDeferredShadingSceneRenderer::RenderIndirectCapsuleShadows( if (View.IndirectShadowPrimitives.Num() > 0 && View.ViewState) { SCOPED_DRAW_EVENT(RHICmdList, IndirectCapsuleShadows); + SCOPED_GPU_STAT(RHICmdList, Stat_GPU_CapsuleShadows); int32 NumCapsuleShapes = 0; SetupIndirectCapsuleShadows(RHICmdList, View, true, NumCapsuleShapes); @@ -1218,6 +1222,7 @@ void FDeferredShadingSceneRenderer::RenderCapsuleShadowsForMovableSkylight(FRHIC if (View.IndirectShadowPrimitives.Num() > 0 && View.ViewState) { SCOPED_DRAW_EVENT(RHICmdList, IndirectCapsuleShadows); + SCOPED_GPU_STAT(RHICmdList, Stat_GPU_CapsuleShadows); int32 NumCapsuleShapes = 0; SetupIndirectCapsuleShadows(RHICmdList, View, true, NumCapsuleShapes); diff --git a/Engine/Source/Runtime/Renderer/Private/CompositionLighting/CompositionLighting.cpp b/Engine/Source/Runtime/Renderer/Private/CompositionLighting/CompositionLighting.cpp index 215d09021a76..2e1c623e984a 100644 --- a/Engine/Source/Runtime/Renderer/Private/CompositionLighting/CompositionLighting.cpp +++ b/Engine/Source/Runtime/Renderer/Private/CompositionLighting/CompositionLighting.cpp @@ -26,6 +26,11 @@ /** The global center for all deferred lighting activities. */ FCompositionLighting GCompositionLighting; +DECLARE_FLOAT_COUNTER_STAT(TEXT("Composition BeforeBasePass"), Stat_GPU_CompositionBeforeBasePass, STATGROUP_GPU); +DECLARE_FLOAT_COUNTER_STAT(TEXT("Composition PreLighting"), Stat_GPU_CompositionPreLighting, STATGROUP_GPU); +DECLARE_FLOAT_COUNTER_STAT(TEXT("Composition LpvIndirect"), Stat_GPU_CompositionLpvIndirect, STATGROUP_GPU); +DECLARE_FLOAT_COUNTER_STAT(TEXT("Composition PostLighting"), Stat_GPU_CompositionPostLighting, STATGROUP_GPU); + // ------------------------------------------------------- static TAutoConsoleVariable CVarSSSScale( @@ -120,6 +125,7 @@ uint32 ComputeAmbientOcclusionPassCount(const FViewInfo& View) if (!IsLpvIndirectPassRequired(View)) { bEnabled = View.FinalPostProcessSettings.AmbientOcclusionIntensity > 0 + && View.Family->EngineShowFlags.Lighting && View.FinalPostProcessSettings.AmbientOcclusionRadius >= 0.1f && !View.Family->UseDebugViewPS() && (FSSAOHelper::IsBasePassAmbientOcclusionRequired(View) || IsAmbientCubemapPassRequired(View) || IsReflectionEnvironmentActive(View) || IsSkylightActive(View) || View.Family->EngineShowFlags.VisualizeBuffer) @@ -281,6 +287,7 @@ void FCompositionLighting::ProcessBeforeBasePass(FRHICommandListImmediate& RHICm // The graph setup should be finished before this line ---------------------------------------- SCOPED_DRAW_EVENT(RHICmdList, CompositionBeforeBasePass); + SCOPED_GPU_STAT(RHICmdList, Stat_GPU_CompositionBeforeBasePass); CompositeContext.Process(Context.FinalOutput.GetPass(), TEXT("Composition_BeforeBasePass")); } @@ -360,6 +367,7 @@ void FCompositionLighting::ProcessAfterBasePass(FRHICommandListImmediate& RHICmd // The graph setup should be finished before this line ---------------------------------------- SCOPED_DRAW_EVENT(RHICmdList, LightCompositionTasks_PreLighting); + SCOPED_GPU_STAT(RHICmdList, Stat_GPU_CompositionPreLighting); TRefCountPtr& SceneColor = SceneContext.GetSceneColor(); @@ -394,6 +402,7 @@ void FCompositionLighting::ProcessLpvIndirect(FRHICommandListImmediate& RHICmdLi // The graph setup should be finished before this line ---------------------------------------- SCOPED_DRAW_EVENT(RHICmdList, CompositionLpvIndirect); + SCOPED_GPU_STAT(RHICmdList, Stat_GPU_CompositionLpvIndirect); // we don't replace the final element with the scenecolor because this is what those passes should do by themself @@ -457,6 +466,7 @@ void FCompositionLighting::ProcessAfterLighting(FRHICommandListImmediate& RHICmd // The graph setup should be finished before this line ---------------------------------------- SCOPED_DRAW_EVENT(RHICmdList, CompositionAfterLighting); + SCOPED_GPU_STAT(RHICmdList, Stat_GPU_CompositionPostLighting); // we don't replace the final element with the scenecolor because this is what those passes should do by themself diff --git a/Engine/Source/Runtime/Renderer/Private/CompositionLighting/PostProcessDeferredDecals.cpp b/Engine/Source/Runtime/Renderer/Private/CompositionLighting/PostProcessDeferredDecals.cpp index 27a03d737149..54fa34c35e2d 100644 --- a/Engine/Source/Runtime/Renderer/Private/CompositionLighting/PostProcessDeferredDecals.cpp +++ b/Engine/Source/Runtime/Renderer/Private/CompositionLighting/PostProcessDeferredDecals.cpp @@ -13,6 +13,89 @@ #include "SceneUtils.h" #include "DecalRenderingShared.h" + + + +static TAutoConsoleVariable CVarGenerateDecalRTWriteMaskTexture( + TEXT("r.Decal.GenerateRTWriteMaskTexture"), + 1, + TEXT("Turn on or off generation of the RT write mask texture for decals\n"), + ECVF_Default); + + + + +class FRTWriteMaskDecodeCS : public FGlobalShader +{ + DECLARE_SHADER_TYPE(FRTWriteMaskDecodeCS, Global); + + static bool ShouldCache(EShaderPlatform Platform) + { + return IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM5); + } + + static void ModifyCompilationEnvironment(EShaderPlatform Platform, FShaderCompilerEnvironment& OutEnvironment) + { + FGlobalShader::ModifyCompilationEnvironment(Platform, OutEnvironment); + } + + FRTWriteMaskDecodeCS() {} + +public: + FShaderParameter OutCombinedRTWriteMask; // UAV + FShaderResourceParameter RTWriteMaskInput0; // SRV + FShaderResourceParameter RTWriteMaskInput1; // SRV + FShaderResourceParameter RTWriteMaskInput2; // SRV + FShaderParameter UtilizeMask; // SRV + + FRTWriteMaskDecodeCS(const ShaderMetaType::CompiledShaderInitializerType& Initializer) + : FGlobalShader(Initializer) + { + RTWriteMaskDimensions.Bind(Initializer.ParameterMap, TEXT("RTWriteMaskDimensions")); + OutCombinedRTWriteMask.Bind(Initializer.ParameterMap, TEXT("OutCombinedRTWriteMask")); + RTWriteMaskInput0.Bind(Initializer.ParameterMap, TEXT("RTWriteMaskInput0")); + RTWriteMaskInput1.Bind(Initializer.ParameterMap, TEXT("RTWriteMaskInput1")); + RTWriteMaskInput2.Bind(Initializer.ParameterMap, TEXT("RTWriteMaskInput2")); + UtilizeMask.Bind(Initializer.ParameterMap, TEXT("UtilizeMask")); + } + + void SetCS(FRHICommandList& RHICmdList, const FRenderingCompositePassContext& Context, const FSceneView& View) + { + const FComputeShaderRHIParamRef ShaderRHI = GetComputeShader(); + + FGlobalShader::SetParameters(RHICmdList, ShaderRHI, Context.View); + //PostprocessParameter.SetCS(ShaderRHI, Context, Context.RHICmdList, TStaticSamplerState::GetRHI()); + + FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList); + FTextureRHIRef DBufferTex = SceneContext.DBufferA->GetRenderTargetItem().TargetableTexture; + FIntPoint Dims(FPlatformMath::CeilToInt(DBufferTex->GetTexture2D()->GetSizeX() / 8.0f), FPlatformMath::CeilToInt(DBufferTex->GetTexture2D()->GetSizeY() / 8.0f)); + + SetShaderValue(Context.RHICmdList, ShaderRHI, RTWriteMaskDimensions, Dims); + SetSRVParameter(Context.RHICmdList, ShaderRHI, RTWriteMaskInput0, SceneContext.DBufferA->GetRenderTargetItem().RTWriteMaskBufferRHI_SRV); + SetSRVParameter(Context.RHICmdList, ShaderRHI, RTWriteMaskInput1, SceneContext.DBufferB->GetRenderTargetItem().RTWriteMaskBufferRHI_SRV); + SetSRVParameter(Context.RHICmdList, ShaderRHI, RTWriteMaskInput2, SceneContext.DBufferC->GetRenderTargetItem().RTWriteMaskBufferRHI_SRV); + int32 UseMask = CVarGenerateDecalRTWriteMaskTexture.GetValueOnRenderThread(); + SetShaderValue(Context.RHICmdList, ShaderRHI, UtilizeMask, UseMask); + } + + virtual bool Serialize(FArchive& Ar) override + { + bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar); + Ar << RTWriteMaskDimensions; + Ar << OutCombinedRTWriteMask; + Ar << RTWriteMaskInput0; + Ar << RTWriteMaskInput1; + Ar << RTWriteMaskInput2; + Ar << UtilizeMask; + return bShaderHasOutdatedParameters; + } + +private: + FShaderParameter RTWriteMaskDimensions; +}; + +IMPLEMENT_SHADER_TYPE(, FRTWriteMaskDecodeCS, TEXT("RTWriteMaskDecode"), TEXT("RTWriteMaskCombineMain"), SF_Compute); + static TAutoConsoleVariable CVarStencilSizeThreshold( TEXT("r.Decal.StencilSizeThreshold"), 0.1f, @@ -477,6 +560,52 @@ const TCHAR* GetStageName(EDecalRenderStage Stage) return TEXT(""); } + +void FRCPassPostProcessDeferredDecals::DecodeRTWriteMask(FRenderingCompositePassContext& Context) +{ + if (GSupportsRenderTargetWriteMask) + { + FRHICommandListImmediate& RHICmdList = Context.RHICmdList; + FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList); + FTextureRHIRef DBufferTex = SceneContext.DBufferA->GetRenderTargetItem().TargetableTexture; + int32 W = FPlatformMath::CeilToInt(DBufferTex->GetTexture2D()->GetSizeX() / 16.0f); + int32 H = FPlatformMath::CeilToInt(DBufferTex->GetTexture2D()->GetSizeY() / 8.0f); + FIntPoint RTWriteMaskDims(W, H); + + FIntRect ViewRect(0, 0, DBufferTex->GetTexture2D()->GetSizeX(), DBufferTex->GetTexture2D()->GetSizeY()); + + TShaderMapRef< FRTWriteMaskDecodeCS > ComputeShader(Context.GetShaderMap()); + + SetRenderTarget(Context.RHICmdList, FTextureRHIRef(), FTextureRHIRef()); + Context.SetViewportAndCallRHI(ViewRect); + Context.RHICmdList.SetComputeShader(ComputeShader->GetComputeShader()); + + // set destination + Context.RHICmdList.SetUAVParameter(ComputeShader->GetComputeShader(), ComputeShader->OutCombinedRTWriteMask.GetBaseIndex(), SceneContext.DBufferMask->GetRenderTargetItem().UAV); + ComputeShader->SetCS(Context.RHICmdList, Context, Context.View); + + RHICmdList.TransitionResource(EResourceTransitionAccess::EWritable, EResourceTransitionPipeline::EGfxToCompute, SceneContext.DBufferMask->GetRenderTargetItem().UAV); + { + SCOPED_DRAW_EVENTF(Context.RHICmdList, DeferredDecals, TEXT("Combine DBuffer RTWriteMasks")); + FIntPoint ThreadGroupCountValue(FPlatformMath::CeilToInt(RTWriteMaskDims.X / 8.0f), FPlatformMath::CeilToInt(RTWriteMaskDims.Y / 16.0f)); + DispatchComputeShader(Context.RHICmdList, *ComputeShader, ThreadGroupCountValue.X, ThreadGroupCountValue.Y, 1); + } + + // void FD3D11DynamicRHI::RHIGraphicsWaitOnAsyncComputeJob( uint32 FenceIndex ) + Context.RHICmdList.FlushComputeShaderCache(); + + RHICmdList.TransitionResource(EResourceTransitionAccess::EReadable, EResourceTransitionPipeline::EComputeToGfx, SceneContext.DBufferMask->GetRenderTargetItem().UAV); + + RHICmdList.TransitionResource(EResourceTransitionAccess::EMetaData, SceneContext.DBufferA->GetRenderTargetItem().TargetableTexture); + RHICmdList.TransitionResource(EResourceTransitionAccess::EMetaData, SceneContext.DBufferB->GetRenderTargetItem().TargetableTexture); + RHICmdList.TransitionResource(EResourceTransitionAccess::EMetaData, SceneContext.DBufferC->GetRenderTargetItem().TargetableTexture); + + // un-set destination + Context.RHICmdList.SetUAVParameter(ComputeShader->GetComputeShader(), ComputeShader->OutCombinedRTWriteMask.GetBaseIndex(), NULL); + } +} + + void FRCPassPostProcessDeferredDecals::Process(FRenderingCompositePassContext& Context) { FRHICommandListImmediate& RHICmdList = Context.RHICmdList; @@ -488,27 +617,45 @@ void FRCPassPostProcessDeferredDecals::Process(FRenderingCompositePassContext& C SCOPED_DRAW_EVENTF(RHICmdList, DeferredDecals, TEXT("DeferredDecals %s"), GetStageName(CurrentStage)); - if(CurrentStage == DRS_BeforeBasePass) + if (CurrentStage == DRS_BeforeBasePass) { // before BasePass, only if DBuffer is enabled check(bDBuffer); // DBuffer: Decal buffer - FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(SceneContext.GBufferA->GetDesc().Extent, + FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(SceneContext.GBufferA->GetDesc().Extent, PF_B8G8R8A8, FClearValueBinding::None, - TexCreate_None, + TexCreate_None, TexCreate_ShaderResource | TexCreate_RenderTargetable, - false)); + false, + 1, + true, + true)); - if(!SceneContext.DBufferA) + if (GSupportsRenderTargetWriteMask) + { + int32 W = FPlatformMath::CeilToInt(SceneContext.GBufferA->GetDesc().Extent.X / 8.0f); + int32 H = FPlatformMath::CeilToInt(SceneContext.GBufferA->GetDesc().Extent.Y / 8.0f); + FIntPoint RTWriteMaskDims(W, H); + FPooledRenderTargetDesc MaskDesc(FPooledRenderTargetDesc::Create2DDesc(RTWriteMaskDims, + PF_R8_UINT, + FClearValueBinding::White, + TexCreate_None, + TexCreate_UAV | TexCreate_RenderTargetable, + false)); + + GRenderTargetPool.FindFreeElement(Context.RHICmdList, MaskDesc, SceneContext.DBufferMask, TEXT("DBufferMask")); + } + + if (!SceneContext.DBufferA) { Desc.ClearValue = FClearValueBinding::Black; GRenderTargetPool.FindFreeElement(RHICmdList, Desc, SceneContext.DBufferA, TEXT("DBufferA")); } - if(!SceneContext.DBufferB) + if (!SceneContext.DBufferB) { Desc.ClearValue = FClearValueBinding(FLinearColor(128.0f / 255.0f, 128.0f / 255.0f, 128.0f / 255.0f, 1)); GRenderTargetPool.FindFreeElement(RHICmdList, Desc, SceneContext.DBufferB, TEXT("DBufferB")); @@ -516,7 +663,7 @@ void FRCPassPostProcessDeferredDecals::Process(FRenderingCompositePassContext& C Desc.Format = PF_R8G8; - if(!SceneContext.DBufferC) + if (!SceneContext.DBufferC) { Desc.ClearValue = FClearValueBinding(FLinearColor(0, 1, 0, 1)); GRenderTargetPool.FindFreeElement(RHICmdList, Desc, SceneContext.DBufferC, TEXT("DBufferC")); @@ -526,7 +673,7 @@ void FRCPassPostProcessDeferredDecals::Process(FRenderingCompositePassContext& C // and don't get FastClear any more. bool bFirstView = Context.View.Family->Views[0] == &Context.View; - if(bFirstView) + if (bFirstView) { SCOPED_DRAW_EVENT(RHICmdList, DBufferClear); @@ -680,7 +827,6 @@ void FRCPassPostProcessDeferredDecals::Process(FRenderingCompositePassContext& C FDecalRendering::SetShader(RHICmdList, View, DecalData, FrustumComponentToClip); RHICmdList.DrawIndexedPrimitive(GetUnitCubeIndexBuffer(), PT_TriangleList, 0, 0, 8, 0, ARRAY_COUNT(GCubeIndices) / 3, 1); - RenderTargetManager.bGufferADirty |= (RenderTargetManager.TargetsToResolve[FDecalRenderTargetManager::GBufferAIndex] != nullptr); } @@ -688,6 +834,15 @@ void FRCPassPostProcessDeferredDecals::Process(FRenderingCompositePassContext& C // Clear stencil to 0, which is the assumed default by other passes RHICmdList.Clear(false, FLinearColor::White, false, (float)ERHIZBuffer::FarPlane, true, 0, FIntRect()); } + + if (CurrentStage == DRS_BeforeBasePass) + { + // combine DBuffer RTWriteMasks; will end up in one texture we can load from in the base pass PS and decide whether to do the actual work or not + RenderTargetManager.FlushMetaData(); + DecodeRTWriteMask(Context); + } + + RenderTargetManager.ResolveTargets(); } if (CurrentStage == DRS_BeforeBasePass) @@ -708,4 +863,4 @@ FPooledRenderTargetDesc FRCPassPostProcessDeferredDecals::ComputeOutputDesc(EPas Ret.DebugName = TEXT("DeferredDecals"); return Ret; -} \ No newline at end of file +} diff --git a/Engine/Source/Runtime/Renderer/Private/CompositionLighting/PostProcessDeferredDecals.h b/Engine/Source/Runtime/Renderer/Private/CompositionLighting/PostProcessDeferredDecals.h index 5527eb6d3ed5..b8ba4fcac35b 100644 --- a/Engine/Source/Runtime/Renderer/Private/CompositionLighting/PostProcessDeferredDecals.h +++ b/Engine/Source/Runtime/Renderer/Private/CompositionLighting/PostProcessDeferredDecals.h @@ -25,6 +25,7 @@ public: private: // see EDecalRenderStage EDecalRenderStage CurrentStage; + void DecodeRTWriteMask(FRenderingCompositePassContext& Context); }; bool IsDBufferEnabled(); @@ -88,6 +89,11 @@ struct FDecalRenderTargetManager // destructor ~FDecalRenderTargetManager() + { + + } + + void ResolveTargets() { FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList); @@ -105,8 +111,12 @@ struct FDecalRenderTargetManager { RHICmdList.CopyToResolveTarget(TargetsToResolve[i], TargetsToResolve[i], true, ResolveParams); } - } + } + } + void FlushMetaData() + { + RHICmdList.TransitionResource(EResourceTransitionAccess::EMetaData, nullptr); } void SetRenderTargetMode(FDecalRenderingCommon::ERenderTargetMode CurrentRenderTargetMode, bool bHasNormal) diff --git a/Engine/Source/Runtime/Renderer/Private/DeferredShadingRenderer.cpp b/Engine/Source/Runtime/Renderer/Private/DeferredShadingRenderer.cpp index 764af9031d94..832ec8d03fb2 100644 --- a/Engine/Source/Runtime/Renderer/Private/DeferredShadingRenderer.cpp +++ b/Engine/Source/Runtime/Renderer/Private/DeferredShadingRenderer.cpp @@ -128,6 +128,10 @@ DECLARE_CYCLE_STAT(TEXT("DeferredShadingSceneRenderer RenderFinish"), STAT_FDefe DECLARE_CYCLE_STAT(TEXT("OcclusionSubmittedFence Dispatch"), STAT_OcclusionSubmittedFence_Dispatch, STATGROUP_SceneRendering); DECLARE_CYCLE_STAT(TEXT("OcclusionSubmittedFence Wait"), STAT_OcclusionSubmittedFence_Wait, STATGROUP_SceneRendering); +DECLARE_FLOAT_COUNTER_STAT(TEXT("Postprocessing"), Stat_GPU_Postprocessing, STATGROUP_GPU); +DECLARE_FLOAT_COUNTER_STAT(TEXT("HZB"), Stat_GPU_HZB, STATGROUP_GPU); +DECLARE_FLOAT_COUNTER_STAT(TEXT("[unaccounted]"), Stat_GPU_Unaccounted, STATGROUP_GPU); + bool ShouldForceFullDepthPass(ERHIFeatureLevel::Type FeatureLevel) { static IConsoleVariable* CDBufferVar = IConsoleManager::Get().FindConsoleVariable(TEXT("r.DBuffer")); @@ -431,6 +435,8 @@ void FDeferredShadingSceneRenderer::RenderOcclusion(FRHICommandListImmediate& RH { FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList); + SCOPED_GPU_STAT(RHICmdList, Stat_GPU_HZB); + { // Update the quarter-sized depth buffer with the current contents of the scene depth texture. // This needs to happen before occlusion tests, which makes use of the small depth buffer. @@ -543,6 +549,10 @@ void FDeferredShadingSceneRenderer::Render(FRHICommandListImmediate& RHICmdList) return; } SCOPED_DRAW_EVENT(RHICmdList, Scene); + + // Anything rendered inside Render() which isn't accounted for will fall into this stat + // This works because child stat events do not contribute to their parents' times (see GPU_STATS_CHILD_TIMES_INCLUDED) + SCOPED_GPU_STAT(RHICmdList, Stat_GPU_Unaccounted); { SCOPE_CYCLE_COUNTER(STAT_FDeferredShadingSceneRenderer_Render_Init); @@ -1186,6 +1196,8 @@ void FDeferredShadingSceneRenderer::Render(FRHICommandListImmediate& RHICmdList) if (ViewFamily.bResolveScene) { SCOPED_DRAW_EVENT(RHICmdList, PostProcessing); + SCOPED_GPU_STAT(RHICmdList, Stat_GPU_Postprocessing); + SCOPE_CYCLE_COUNTER(STAT_FinishRenderViewTargetTime); RHICmdList.SetCurrentStat(GET_STATID(STAT_CLM_PostProcessing)); @@ -1458,4 +1470,4 @@ void FDeferredShadingSceneRenderer::CopyStencilToLightingChannelTexture(FRHIComm true, ResolveParams); } -} \ No newline at end of file +} diff --git a/Engine/Source/Runtime/Renderer/Private/DepthRendering.cpp b/Engine/Source/Runtime/Renderer/Private/DepthRendering.cpp index 1f8f9b331b12..bb2675317474 100644 --- a/Engine/Source/Runtime/Renderer/Private/DepthRendering.cpp +++ b/Engine/Source/Runtime/Renderer/Private/DepthRendering.cpp @@ -45,6 +45,8 @@ const TCHAR* GetDepthDrawingModeString(EDepthDrawingMode Mode) return TEXT(""); } +DECLARE_FLOAT_COUNTER_STAT(TEXT("Prepass"), Stat_GPU_Prepass, STATGROUP_GPU); + /** * A vertex shader for rendering the depth of a mesh. */ @@ -196,19 +198,33 @@ public: FDepthOnlyPS(const ShaderMetaType::CompiledShaderInitializerType& Initializer): FMeshMaterialShader(Initializer) - {} + { + ApplyDepthOffsetParameter.Bind(Initializer.ParameterMap, TEXT("bApplyDepthOffset")); + } FDepthOnlyPS() {} void SetParameters(FRHICommandList& RHICmdList, const FMaterialRenderProxy* MaterialRenderProxy,const FMaterial& MaterialResource,const FSceneView* View) { FMeshMaterialShader::SetParameters(RHICmdList, GetPixelShader(),MaterialRenderProxy,MaterialResource,*View,ESceneRenderTargetsMode::DontSet); + + // For debug view shaders, don't apply the depth offset as their base pass PS are using global shaders with depth equal. + SetShaderValue(RHICmdList, GetPixelShader(), ApplyDepthOffsetParameter, !View || !View->Family->UseDebugViewPS()); } void SetMesh(FRHICommandList& RHICmdList, const FVertexFactory* VertexFactory,const FSceneView& View,const FPrimitiveSceneProxy* Proxy,const FMeshBatchElement& BatchElement,const FMeshDrawingRenderState& DrawRenderState) { FMeshMaterialShader::SetMesh(RHICmdList, GetPixelShader(),VertexFactory,View,Proxy,BatchElement,DrawRenderState); } + + virtual bool Serialize(FArchive& Ar) override + { + bool bShaderHasOutdatedParameters = FMeshMaterialShader::Serialize(Ar); + Ar << ApplyDepthOffsetParameter; + return bShaderHasOutdatedParameters; + } + + FShaderParameter ApplyDepthOffsetParameter; }; IMPLEMENT_MATERIAL_SHADER_TYPE(,FDepthOnlyPS,TEXT("DepthOnlyPixelShader"),TEXT("Main"),SF_Pixel); @@ -1071,6 +1087,7 @@ bool FDeferredShadingSceneRenderer::RenderPrePass(FRHICommandListImmediate& RHIC SCOPED_DRAW_EVENTF(RHICmdList, PrePass, TEXT("PrePass %s %s"), GetDepthDrawingModeString(EarlyZPassMode), GetDepthPassReason(bDitheredLODTransitionsUseStencil, FeatureLevel)); SCOPE_CYCLE_COUNTER(STAT_DepthDrawTime); + SCOPED_GPU_STAT(RHICmdList, Stat_GPU_Prepass); bool bDirty = false; bool bDidPrePre = false; diff --git a/Engine/Source/Runtime/Renderer/Private/DistortionRendering.cpp b/Engine/Source/Runtime/Renderer/Private/DistortionRendering.cpp index 4b5126e86a17..067db6241c2f 100644 --- a/Engine/Source/Runtime/Renderer/Private/DistortionRendering.cpp +++ b/Engine/Source/Runtime/Renderer/Private/DistortionRendering.cpp @@ -13,6 +13,8 @@ #include "SceneFilterRendering.h" #include "SceneUtils.h" +DECLARE_FLOAT_COUNTER_STAT(TEXT("Distortion"), Stat_GPU_Distortion, STATGROUP_GPU); + /** * A pixel shader for rendering the full screen refraction pass */ @@ -832,6 +834,7 @@ void FSceneRenderer::RenderDistortion(FRHICommandListImmediate& RHICmdList) { QUICK_SCOPE_CYCLE_COUNTER(STAT_FSceneRenderer_RenderDistortion); SCOPED_DRAW_EVENT(RHICmdList, Distortion); + SCOPED_GPU_STAT(RHICmdList, Stat_GPU_Distortion); // do we need to render the distortion pass? bool bRender=false; diff --git a/Engine/Source/Runtime/Renderer/Private/FogRendering.cpp b/Engine/Source/Runtime/Renderer/Private/FogRendering.cpp index 46b1870e91a5..26f7990faa1e 100644 --- a/Engine/Source/Runtime/Renderer/Private/FogRendering.cpp +++ b/Engine/Source/Runtime/Renderer/Private/FogRendering.cpp @@ -8,6 +8,8 @@ #include "ScenePrivate.h" #include "SceneUtils.h" +DECLARE_FLOAT_COUNTER_STAT(TEXT("Fog"), Stat_GPU_Fog, STATGROUP_GPU); + #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) static TAutoConsoleVariable CVarFogStartDistance( TEXT("r.FogStartDistance"), @@ -320,6 +322,7 @@ bool FDeferredShadingSceneRenderer::RenderFog(FRHICommandListImmediate& RHICmdLi const FViewInfo& View = Views[ViewIndex]; SCOPED_DRAW_EVENTF(RHICmdList, Fog, TEXT("ExponentialHeightFog %dx%d"), View.ViewRect.Width(), View.ViewRect.Height()); + SCOPED_GPU_STAT(RHICmdList, Stat_GPU_Fog); if (View.IsPerspectiveProjection() == false) { diff --git a/Engine/Source/Runtime/Renderer/Private/LightPropagationVolume.cpp b/Engine/Source/Runtime/Renderer/Private/LightPropagationVolume.cpp index cca7aba001c5..0b18553ef2c4 100644 --- a/Engine/Source/Runtime/Renderer/Private/LightPropagationVolume.cpp +++ b/Engine/Source/Runtime/Renderer/Private/LightPropagationVolume.cpp @@ -17,6 +17,8 @@ #include "SceneUtils.h" #include "LightPropagationVolumeBlendable.h" +DECLARE_FLOAT_COUNTER_STAT(TEXT("LPV"), Stat_GPU_LPV, STATGROUP_GPU); + static TAutoConsoleVariable CVarLightPropagationVolume( TEXT("r.LightPropagationVolume"), 0, @@ -1570,6 +1572,7 @@ void FDeferredShadingSceneRenderer::ClearLPVs(FRHICommandListImmediate& RHICmdLi if(LightPropagationVolume) { + SCOPED_GPU_STAT(RHICmdList, Stat_GPU_LPV); LightPropagationVolume->InitSettings(RHICmdList, Views[ViewIndex]); LightPropagationVolume->Clear(RHICmdList, View); } @@ -1598,7 +1601,8 @@ void FDeferredShadingSceneRenderer::UpdateLPVs(FRHICommandListImmediate& RHICmdL { // SCOPED_DRAW_EVENT(RHICmdList, UpdateLPVs); // SCOPE_CYCLE_COUNTER(STAT_UpdateLPVs); - + SCOPED_GPU_STAT(RHICmdList, Stat_GPU_LPV); + LightPropagationVolume->Update(RHICmdList, View); } } diff --git a/Engine/Source/Runtime/Renderer/Private/LightRendering.cpp b/Engine/Source/Runtime/Renderer/Private/LightRendering.cpp index 5a503469aadd..169cebf5e347 100644 --- a/Engine/Source/Runtime/Renderer/Private/LightRendering.cpp +++ b/Engine/Source/Runtime/Renderer/Private/LightRendering.cpp @@ -13,6 +13,7 @@ #include "LightPropagationVolume.h" #include "SceneUtils.h" +DECLARE_FLOAT_COUNTER_STAT(TEXT("Lights"), Stat_GPU_Lights, STATGROUP_GPU); IMPLEMENT_UNIFORM_BUFFER_STRUCT(FDeferredLightUniformStruct,TEXT("DeferredLightUniforms")); @@ -323,6 +324,8 @@ uint32 GetShadowQuality(); void FDeferredShadingSceneRenderer::RenderLights(FRHICommandListImmediate& RHICmdList) { SCOPED_DRAW_EVENT(RHICmdList, Lights); + SCOPED_GPU_STAT(RHICmdList, Stat_GPU_Lights); + bool bStencilBufferDirty = false; // The stencil buffer should've been cleared to 0 already diff --git a/Engine/Source/Runtime/Renderer/Private/MobileBasePassRendering.h b/Engine/Source/Runtime/Renderer/Private/MobileBasePassRendering.h index 109481e0f018..1dba30204267 100644 --- a/Engine/Source/Runtime/Renderer/Private/MobileBasePassRendering.h +++ b/Engine/Source/Runtime/Renderer/Private/MobileBasePassRendering.h @@ -708,6 +708,10 @@ public: // Modulate with the existing scene color RHICmdList.SetBlendState(TStaticBlendState::GetRHI()); break; + case BLEND_AlphaComposite: + // Blend with existing scene color. New color is already pre-multiplied by alpha. + RHICmdList.SetBlendState(TStaticBlendState::GetRHI()); + break; }; } } diff --git a/Engine/Source/Runtime/Renderer/Private/PostProcess/RenderTargetPool.cpp b/Engine/Source/Runtime/Renderer/Private/PostProcess/RenderTargetPool.cpp index 5fa39ca42a5f..01646f66c78e 100644 --- a/Engine/Source/Runtime/Renderer/Private/PostProcess/RenderTargetPool.cpp +++ b/Engine/Source/Runtime/Renderer/Private/PostProcess/RenderTargetPool.cpp @@ -314,6 +314,13 @@ bool FRenderTargetPool::FindFreeElement(FRHICommandList& RHICmdList, const FPool Desc.NumSamples ); + if (GSupportsRenderTargetWriteMask && Desc.bCreateRenderTargetWriteMask) + { + Found->RenderTargetItem.RTWriteMaskDataBufferRHI = RHICreateRTWriteMaskBuffer((FTexture2DRHIRef&)Found->RenderTargetItem.TargetableTexture); + Found->RenderTargetItem.RTWriteMaskBufferRHI_SRV = RHICreateShaderResourceView(Found->RenderTargetItem.RTWriteMaskDataBufferRHI); + } + + if( Desc.NumMips > 1 ) { Found->RenderTargetItem.MipSRVs.SetNum( Desc.NumMips ); diff --git a/Engine/Source/Runtime/Renderer/Private/PostProcess/SceneRenderTargets.cpp b/Engine/Source/Runtime/Renderer/Private/PostProcess/SceneRenderTargets.cpp index 408ea0f8d64c..d29a683d5f95 100644 --- a/Engine/Source/Runtime/Renderer/Private/PostProcess/SceneRenderTargets.cpp +++ b/Engine/Source/Runtime/Renderer/Private/PostProcess/SceneRenderTargets.cpp @@ -199,6 +199,7 @@ FSceneRenderTargets::FSceneRenderTargets(const FViewInfo& View, const FSceneRend , DBufferA(GRenderTargetPool.MakeSnapshot(SnapshotSource.DBufferA)) , DBufferB(GRenderTargetPool.MakeSnapshot(SnapshotSource.DBufferB)) , DBufferC(GRenderTargetPool.MakeSnapshot(SnapshotSource.DBufferC)) + , DBufferMask(GRenderTargetPool.MakeSnapshot(SnapshotSource.DBufferMask)) , ScreenSpaceAO(GRenderTargetPool.MakeSnapshot(SnapshotSource.ScreenSpaceAO)) , QuadOverdrawBuffer(GRenderTargetPool.MakeSnapshot(SnapshotSource.QuadOverdrawBuffer)) , CustomDepth(GRenderTargetPool.MakeSnapshot(SnapshotSource.CustomDepth)) @@ -833,7 +834,7 @@ void FSceneRenderTargets::AllocGBufferTargets(FRHICommandList& RHICmdList) GBufferResourceStruct.GBufferDTexture = GBufferDToUse.ShaderResourceTexture; GBufferResourceStruct.GBufferETexture = GBufferEToUse.ShaderResourceTexture; GBufferResourceStruct.GBufferVelocityTexture = GBufferVelocityToUse.ShaderResourceTexture; - + GBufferResourceStruct.GBufferATextureNonMS = GBufferAToUse.ShaderResourceTexture; GBufferResourceStruct.GBufferBTextureNonMS = GBufferBToUse.ShaderResourceTexture; GBufferResourceStruct.GBufferCTextureNonMS = GBufferCToUse.ShaderResourceTexture; @@ -2320,6 +2321,7 @@ void FDeferredPixelShaderParameters::Bind(const FShaderParameterMap& ParameterMa CustomDepthTexture.Bind(ParameterMap,TEXT("CustomDepthTexture")); CustomDepthTextureSampler.Bind(ParameterMap,TEXT("CustomDepthTextureSampler")); CustomStencilTexture.Bind(ParameterMap,TEXT("CustomStencilTexture")); + DBufferRenderMask.Bind(ParameterMap, TEXT("DBufferMask")); } bool IsDBufferEnabled(); @@ -2332,7 +2334,7 @@ void FDeferredPixelShaderParameters::Set(TRHICmdList& RHICmdList, const ShaderRH SceneTextureParameters.Set(RHICmdList, ShaderRHI, View, TextureMode, SF_Point); // if() is purely an optimization and could be removed - if(IsDBufferEnabled()) + if (IsDBufferEnabled()) { IPooledRenderTarget* DBufferA = SceneContext.DBufferA ? SceneContext.DBufferA : GSystemTextures.BlackDummy; IPooledRenderTarget* DBufferB = SceneContext.DBufferB ? SceneContext.DBufferB : GSystemTextures.BlackDummy; @@ -2342,6 +2344,19 @@ void FDeferredPixelShaderParameters::Set(TRHICmdList& RHICmdList, const ShaderRH SetTextureParameter(RHICmdList, ShaderRHI, DBufferATexture, DBufferATextureSampler, TStaticSamplerState<>::GetRHI(), DBufferA->GetRenderTargetItem().ShaderResourceTexture); SetTextureParameter(RHICmdList, ShaderRHI, DBufferBTexture, DBufferBTextureSampler, TStaticSamplerState<>::GetRHI(), DBufferB->GetRenderTargetItem().ShaderResourceTexture); SetTextureParameter(RHICmdList, ShaderRHI, DBufferCTexture, DBufferCTextureSampler, TStaticSamplerState<>::GetRHI(), DBufferC->GetRenderTargetItem().ShaderResourceTexture); + + if (GSupportsRenderTargetWriteMask) + { + if (SceneContext.DBufferMask) + { + SetTextureParameter(RHICmdList, ShaderRHI, DBufferRenderMask, SceneContext.DBufferMask->GetRenderTargetItem().TargetableTexture); + } + else + { + SetTextureParameter(RHICmdList, ShaderRHI, DBufferRenderMask, GSystemTextures.WhiteDummy->GetRenderTargetItem().TargetableTexture); + } + } + SetTextureParameter(RHICmdList, ShaderRHI, DBufferATextureMS, DBufferA->GetRenderTargetItem().TargetableTexture); SetTextureParameter(RHICmdList, ShaderRHI, DBufferBTextureMS, DBufferB->GetRenderTargetItem().TargetableTexture); SetTextureParameter(RHICmdList, ShaderRHI, DBufferCTextureMS, DBufferC->GetRenderTargetItem().TargetableTexture); @@ -2441,6 +2456,7 @@ FArchive& operator<<(FArchive& Ar,FDeferredPixelShaderParameters& Parameters) Ar << Parameters.ScreenSpaceAOTextureNonMS; Ar << Parameters.CustomDepthTextureNonMS; Ar << Parameters.DBufferATexture; + Ar << Parameters.DBufferRenderMask; Ar << Parameters.DBufferATextureSampler; Ar << Parameters.DBufferBTexture; Ar << Parameters.DBufferBTextureSampler; diff --git a/Engine/Source/Runtime/Renderer/Private/PostProcess/SceneRenderTargets.h b/Engine/Source/Runtime/Renderer/Private/PostProcess/SceneRenderTargets.h index fa2ddb0f7c1d..39710f291003 100644 --- a/Engine/Source/Runtime/Renderer/Private/PostProcess/SceneRenderTargets.h +++ b/Engine/Source/Runtime/Renderer/Private/PostProcess/SceneRenderTargets.h @@ -554,6 +554,7 @@ public: TRefCountPtr DBufferA; TRefCountPtr DBufferB; TRefCountPtr DBufferC; + TRefCountPtr DBufferMask; // for AmbientOcclusion, only valid for a short time during the frame to allow reuse TRefCountPtr ScreenSpaceAO; diff --git a/Engine/Source/Runtime/Renderer/Private/PostProcess/ScreenSpaceReflections.cpp b/Engine/Source/Runtime/Renderer/Private/PostProcess/ScreenSpaceReflections.cpp index 01bbde2be763..3e3276ecddd4 100644 --- a/Engine/Source/Runtime/Renderer/Private/PostProcess/ScreenSpaceReflections.cpp +++ b/Engine/Source/Runtime/Renderer/Private/PostProcess/ScreenSpaceReflections.cpp @@ -48,6 +48,8 @@ static TAutoConsoleVariable CVarSSRCone( TEXT(" 0 is off (default), 1 is on"), ECVF_RenderThreadSafe); +DECLARE_FLOAT_COUNTER_STAT(TEXT("ScreenSpace Reflections"), Stat_GPU_ScreenSpaceReflections, STATGROUP_GPU); + bool ShouldRenderScreenSpaceReflections(const FViewInfo& View) { if(!View.Family->EngineShowFlags.ScreenSpaceReflections) @@ -335,6 +337,8 @@ void FRCPassPostProcessScreenSpaceReflections::Process(FRenderingCompositePassCo } const FSceneRenderTargetItem& DestRenderTarget = PassOutputs[0].RequestSurface(Context); + + SCOPED_GPU_STAT(RHICmdList, Stat_GPU_ScreenSpaceReflections); if (SSRStencilPrePass) { // ScreenSpaceReflectionsStencil draw event diff --git a/Engine/Source/Runtime/Renderer/Private/ReflectionEnvironment.cpp b/Engine/Source/Runtime/Renderer/Private/ReflectionEnvironment.cpp index bf099b735a8d..0916811ddb07 100644 --- a/Engine/Source/Runtime/Renderer/Private/ReflectionEnvironment.cpp +++ b/Engine/Source/Runtime/Renderer/Private/ReflectionEnvironment.cpp @@ -20,6 +20,8 @@ #include "SceneUtils.h" #include "LightPropagationVolumeBlendable.h" +DECLARE_FLOAT_COUNTER_STAT(TEXT("Reflection Environment"), Stat_GPU_ReflectionEnvironment, STATGROUP_GPU); + /** Tile size for the reflection environment compute shader, tweaked for 680 GTX. */ const int32 GReflectionEnvironmentTileSizeX = 16; const int32 GReflectionEnvironmentTileSizeY = 16; @@ -936,6 +938,7 @@ void FDeferredShadingSceneRenderer::RenderTiledDeferredImageBasedReflections(FRH RenderScreenSpaceReflections(RHICmdList, View, SSROutput); } + SCOPED_GPU_STAT(RHICmdList, Stat_GPU_ReflectionEnvironment) RenderDeferredPlanarReflections(RHICmdList, false, SSROutput); // ReflectionEnv is assumed to be on when going into this method @@ -1100,6 +1103,7 @@ void FDeferredShadingSceneRenderer::RenderStandardDeferredImageBasedReflections( RenderScreenSpaceReflections(RHICmdList, View, SSROutput); } + SCOPED_GPU_STAT(RHICmdList, Stat_GPU_ReflectionEnvironment) bool bApplyFromSSRTexture = bSSR; if (RenderDeferredPlanarReflections(RHICmdList, true, SSROutput)) @@ -1188,6 +1192,7 @@ void FDeferredShadingSceneRenderer::RenderStandardDeferredImageBasedReflections( { // Apply reflections to screen SCOPED_DRAW_EVENT(RHICmdList, ReflectionApply); + SCOPED_GPU_STAT(RHICmdList, Stat_GPU_ReflectionEnvironment); SceneContext.BeginRenderingSceneColor(RHICmdList, ESimpleRenderTargetMode::EUninitializedColorExistingDepth, FExclusiveDepthStencil::DepthRead_StencilWrite, true); diff --git a/Engine/Source/Runtime/Renderer/Private/RendererScene.cpp b/Engine/Source/Runtime/Renderer/Private/RendererScene.cpp index d3b9f4904bed..095965a618cb 100644 --- a/Engine/Source/Runtime/Renderer/Private/RendererScene.cpp +++ b/Engine/Source/Runtime/Renderer/Private/RendererScene.cpp @@ -509,7 +509,7 @@ FScene::FReadOnlyCVARCache::FReadOnlyCVARCache() const bool bShowMissmatchedLowQualityLightmapsWarning = (bEnableLowQualityLightmaps) != (GEngine->bShouldGenerateLowQualityLightmaps_DEPRECATED); if ( bShowMissmatchedLowQualityLightmapsWarning ) { - UE_LOG(LogRenderer, Warning, TEXT("Missmatch between bShouldGenerateLowQualityLightmaps(%d) and r.SupportLowQualityLightmaps(%d), UEngine::bShouldGenerateLowQualityLightmaps has been depricated please use r.SupportLowQualityLightmaps instead"), GEngine->bShouldGenerateLowQualityLightmaps_DEPRECATED, bEnableLowQualityLightmaps); + UE_LOG(LogRenderer, Warning, TEXT("Mismatch between bShouldGenerateLowQualityLightmaps(%d) and r.SupportLowQualityLightmaps(%d), UEngine::bShouldGenerateLowQualityLightmaps has been deprecated please use r.SupportLowQualityLightmaps instead"), GEngine->bShouldGenerateLowQualityLightmaps_DEPRECATED, bEnableLowQualityLightmaps); } } diff --git a/Engine/Source/Runtime/Renderer/Private/SceneCaptureRendering.cpp b/Engine/Source/Runtime/Renderer/Private/SceneCaptureRendering.cpp index 30e1903efba4..e89e9cc8d195 100644 --- a/Engine/Source/Runtime/Renderer/Private/SceneCaptureRendering.cpp +++ b/Engine/Source/Runtime/Renderer/Private/SceneCaptureRendering.cpp @@ -215,14 +215,13 @@ static void UpdateSceneCaptureContent_RenderThread( FRenderTarget* RenderTarget, FTexture* RenderTargetTexture, const FName OwnerName, - const FResolveParams& ResolveParams, - ESceneCaptureSource CaptureSource) + const FResolveParams& ResolveParams) { FMemMark MemStackMark(FMemStack::Get()); // update any resources that needed a deferred update FDeferredUpdateResource::UpdateResources(RHICmdList); - bool bUseSceneTextures = CaptureSource != SCS_FinalColorLDR; + bool bUseSceneTextures = SceneRenderer->ViewFamily.SceneCaptureSource != SCS_FinalColorLDR; { #if WANTS_DRAW_MESH_EVENTS @@ -310,7 +309,7 @@ static void UpdateSceneCaptureContent_RenderThread( } else if (bUseSceneTextures) { - // Note: When the CaptureSource requires scene textures, the copy will be done in CopySceneCaptureComponentToTarget while the GBuffers are still alive for the frame + // Note: When the ViewFamily.SceneCaptureSource requires scene textures, the copy will be done in CopySceneCaptureComponentToTarget while the GBuffers are still alive for the frame } RHICmdList.CopyToResolveTarget(RenderTarget->GetRenderTargetTexture(), RenderTargetTexture->TextureRHI, false, ResolveParams); @@ -532,14 +531,13 @@ void FScene::UpdateSceneCaptureContents(USceneCaptureComponent2D* CaptureCompone FTextureRenderTargetResource* TextureRenderTarget = CaptureComponent->TextureTarget->GameThread_GetRenderTargetResource(); const FName OwnerName = CaptureComponent->GetOwner() ? CaptureComponent->GetOwner()->GetFName() : NAME_None; - ENQUEUE_UNIQUE_RENDER_COMMAND_FOURPARAMETER( + ENQUEUE_UNIQUE_RENDER_COMMAND_THREEPARAMETER( CaptureCommand, FSceneRenderer*, SceneRenderer, SceneRenderer, FTextureRenderTargetResource*, TextureRenderTarget, TextureRenderTarget, FName, OwnerName, OwnerName, - ESceneCaptureSource, CaptureSource, CaptureComponent->CaptureSource, { - UpdateSceneCaptureContent_RenderThread(RHICmdList, SceneRenderer, TextureRenderTarget, TextureRenderTarget, OwnerName, FResolveParams(), CaptureSource); + UpdateSceneCaptureContent_RenderThread(RHICmdList, SceneRenderer, TextureRenderTarget, TextureRenderTarget, OwnerName, FResolveParams()); }); } } @@ -603,6 +601,7 @@ void FScene::UpdateSceneCaptureContents(USceneCaptureComponentCube* CaptureCompo BuildProjectionMatrix(CaptureSize, ECameraProjectionMode::Perspective, FOV, 1.0f, ProjectionMatrix); FSceneRenderer* SceneRenderer = CreateSceneRendererForSceneCapture(this, CaptureComponent, CaptureComponent->TextureTarget->GameThread_GetRenderTargetResource(), CaptureSize, ViewRotationMatrix, Location, ProjectionMatrix, CaptureComponent->MaxViewDistanceOverride, true, false, NULL, 0); + SceneRenderer->ViewFamily.SceneCaptureSource = SCS_SceneColorHDR; FTextureRenderTargetCubeResource* TextureRenderTarget = static_cast(CaptureComponent->TextureTarget->GameThread_GetRenderTargetResource()); const FName OwnerName = CaptureComponent->GetOwner() ? CaptureComponent->GetOwner()->GetFName() : NAME_None; @@ -614,7 +613,7 @@ void FScene::UpdateSceneCaptureContents(USceneCaptureComponentCube* CaptureCompo FName, OwnerName, OwnerName, ECubeFace, TargetFace, TargetFace, { - UpdateSceneCaptureContent_RenderThread(RHICmdList, SceneRenderer, TextureRenderTarget, TextureRenderTarget, OwnerName, FResolveParams(FResolveRect(), TargetFace), SCS_SceneColorHDR); + UpdateSceneCaptureContent_RenderThread(RHICmdList, SceneRenderer, TextureRenderTarget, TextureRenderTarget, OwnerName, FResolveParams(FResolveRect(), TargetFace)); }); } } diff --git a/Engine/Source/Runtime/Renderer/Private/SceneRendering.cpp b/Engine/Source/Runtime/Renderer/Private/SceneRendering.cpp index a1fbe08517fa..1e98edcf8f5c 100644 --- a/Engine/Source/Runtime/Renderer/Private/SceneRendering.cpp +++ b/Engine/Source/Runtime/Renderer/Private/SceneRendering.cpp @@ -29,6 +29,8 @@ extern ENGINE_API FLightMap2D* GDebugSelectedLightmap; extern ENGINE_API UPrimitiveComponent* GDebugSelectedComponent; +DECLARE_FLOAT_COUNTER_STAT(TEXT("Custom Depth"), Stat_GPU_CustomDepth, STATGROUP_GPU); + /** * Console variable controlling whether or not occlusion queries are allowed. */ @@ -1688,6 +1690,7 @@ void FSceneRenderer::RenderCustomDepthPass(FRHICommandListImmediate& RHICmdList) if (SceneContext.BeginRenderingCustomDepth(RHICmdList, bPrimitives)) { SCOPED_DRAW_EVENT(RHICmdList, CustomDepth); + SCOPED_GPU_STAT(RHICmdList, Stat_GPU_CustomDepth); for(int32 ViewIndex = 0;ViewIndex < Views.Num();ViewIndex++) { @@ -1870,6 +1873,8 @@ static void RenderViewFamily_RenderThread(FRHICommandListImmediate& RHICmdList, { SCOPE_CYCLE_COUNTER(STAT_TotalSceneRenderingTime); + GPU_STATS_UPDATE(RHICmdList); + if(SceneRenderer->ViewFamily.EngineShowFlags.HitProxies) { // Render the scene's hit proxies. @@ -2025,6 +2030,9 @@ void FRendererModule::BeginRenderingViewFamily(FCanvas* Canvas, FSceneViewFamily if (!SceneRenderer->ViewFamily.EngineShowFlags.HitProxies) { + USceneCaptureComponent2D::UpdateDeferredCaptures(Scene); + USceneCaptureComponentCube::UpdateDeferredCaptures(Scene); + for (int32 ReflectionIndex = 0; ReflectionIndex < SceneRenderer->Scene->PlanarReflections_GameThread.Num(); ReflectionIndex++) { UPlanarReflectionComponent* ReflectionComponent = SceneRenderer->Scene->PlanarReflections_GameThread[ReflectionIndex]; diff --git a/Engine/Source/Runtime/Renderer/Private/SceneVisibility.cpp b/Engine/Source/Runtime/Renderer/Private/SceneVisibility.cpp index 5b8041d0c414..f1b0a0d19dba 100644 --- a/Engine/Source/Runtime/Renderer/Private/SceneVisibility.cpp +++ b/Engine/Source/Runtime/Renderer/Private/SceneVisibility.cpp @@ -2638,7 +2638,10 @@ void FSceneRenderer::PostVisibilityFrameSetup(FILCUpdatePrimTaskData& OutILCTask { FSphere Bounds = Proxy->GetBoundingSphere(); float DistanceSquared = (Bounds.Center - View.ViewMatrices.ViewOrigin).SizeSquared(); - const bool bDrawLight = FMath::Square( FMath::Min( 0.0002f, GMinScreenRadiusForLights / Bounds.W ) * View.LODDistanceFactor ) * DistanceSquared < 1.0f; + float MaxDistSquared = Proxy->GetMaxDrawDistance() * Proxy->GetMaxDrawDistance(); + const bool bDrawLight = (FMath::Square(FMath::Min(0.0002f, GMinScreenRadiusForLights / Bounds.W) * View.LODDistanceFactor) * DistanceSquared < 1.0f) + & (MaxDistSquared == 0 || DistanceSquared < MaxDistSquared); + VisibleLightViewInfo.bInViewFrustum = bDrawLight; } } diff --git a/Engine/Source/Runtime/Renderer/Private/ShadowDepthRendering.cpp b/Engine/Source/Runtime/Renderer/Private/ShadowDepthRendering.cpp index 56f99c2962bc..1b4d6fa33f64 100644 --- a/Engine/Source/Runtime/Renderer/Private/ShadowDepthRendering.cpp +++ b/Engine/Source/Runtime/Renderer/Private/ShadowDepthRendering.cpp @@ -12,6 +12,8 @@ #include "SceneFilterRendering.h" #include "ScreenRendering.h" +DECLARE_FLOAT_COUNTER_STAT(TEXT("Shadow Depths"), Stat_GPU_ShadowDepths, STATGROUP_GPU); + /** * A vertex shader for rendering the depth of a mesh. */ @@ -2143,6 +2145,7 @@ void FSceneRenderer::RenderShadowDepthMaps(FRHICommandListImmediate& RHICmdList) FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList); SCOPED_DRAW_EVENT(RHICmdList, ShadowDepths); + SCOPED_GPU_STAT(RHICmdList, Stat_GPU_ShadowDepths); FSceneRenderer::RenderShadowDepthMapAtlases(RHICmdList); diff --git a/Engine/Source/Runtime/Renderer/Private/ShadowRendering.cpp b/Engine/Source/Runtime/Renderer/Private/ShadowRendering.cpp index 28181570e693..bc44781c7acf 100644 --- a/Engine/Source/Runtime/Renderer/Private/ShadowRendering.cpp +++ b/Engine/Source/Runtime/Renderer/Private/ShadowRendering.cpp @@ -67,6 +67,8 @@ static TAutoConsoleVariable CVarEnableModulatedSelfShadow( TEXT("Allows modulated shadows to affect the shadow caster. (mobile only)"), ECVF_RenderThreadSafe); +DECLARE_FLOAT_COUNTER_STAT(TEXT("ShadowProjection"), Stat_GPU_ShadowProjection, STATGROUP_GPU); + // 0:off, 1:low, 2:med, 3:high, 4:very high, 5:max uint32 GetShadowQuality() { @@ -1278,6 +1280,7 @@ bool FDeferredShadingSceneRenderer::RenderShadowProjections(FRHICommandListImmed { SCOPE_CYCLE_COUNTER(STAT_ProjectedShadowDrawTime); SCOPED_DRAW_EVENT(RHICmdList, ShadowProjectionOnOpaque); + SCOPED_GPU_STAT(RHICmdList, Stat_GPU_ShadowProjection); FVisibleLightInfo& VisibleLightInfo = VisibleLightInfos[LightSceneInfo->Id]; diff --git a/Engine/Source/Runtime/Renderer/Private/ShadowRendering.h b/Engine/Source/Runtime/Renderer/Private/ShadowRendering.h index fa07e5418e65..2ba3d23ea673 100644 --- a/Engine/Source/Runtime/Renderer/Private/ShadowRendering.h +++ b/Engine/Source/Runtime/Renderer/Private/ShadowRendering.h @@ -108,15 +108,22 @@ void SetDeferredLightParameters( const ELightComponentType LightType = (ELightComponentType)LightSceneInfo->Proxy->GetLightType(); + if (LightType == LightType_Point || LightType == LightType_Spot) { // Distance fade FSphere Bounds = LightSceneInfo->Proxy->GetBoundingSphere(); - const float DistanceSquared = ( Bounds.Center - View.ViewMatrices.ViewOrigin ).SizeSquared(); - float Fade = FMath::Square( FMath::Min( 0.0002f, GMinScreenRadiusForLights / Bounds.W ) * View.LODDistanceFactor ) * DistanceSquared; - Fade = FMath::Clamp( 6.0f - 6.0f * Fade, 0.0f, 1.0f ); - DeferredLightUniformsValue.LightColor *= Fade; + const float DistanceSquared = (Bounds.Center - View.ViewMatrices.ViewOrigin).SizeSquared(); + float SizeFade = FMath::Square(FMath::Min(0.0002f, GMinScreenRadiusForLights / Bounds.W) * View.LODDistanceFactor) * DistanceSquared; + SizeFade = FMath::Clamp(6.0f - 6.0f * SizeFade, 0.0f, 1.0f); + + float MaxDist = LightSceneInfo->Proxy->GetMaxDrawDistance(); + float Range = LightSceneInfo->Proxy->GetFadeRange(); + float DistanceFade = MaxDist ? (MaxDist - FMath::Sqrt(DistanceSquared)) / Range : 1.0f; + DistanceFade = FMath::Clamp(DistanceFade, 0.0f, 1.0f); + + DeferredLightUniformsValue.LightColor *= SizeFade * DistanceFade; } DeferredLightUniformsValue.LightingChannelMask = LightSceneInfo->Proxy->GetLightingChannelMask(); diff --git a/Engine/Source/Runtime/Renderer/Private/TranslucentLighting.cpp b/Engine/Source/Runtime/Renderer/Private/TranslucentLighting.cpp index 594b932b5fa8..be84f763e868 100644 --- a/Engine/Source/Runtime/Renderer/Private/TranslucentLighting.cpp +++ b/Engine/Source/Runtime/Renderer/Private/TranslucentLighting.cpp @@ -17,6 +17,8 @@ class FMaterial; /** Whether to allow rendering translucency shadow depths. */ bool GUseTranslucencyShadowDepths = true; + +DECLARE_FLOAT_COUNTER_STAT(TEXT("Translucent Lighting"), Stat_GPU_TranslucentLighting, STATGROUP_GPU); int32 GUseTranslucentLightingVolumes = 1; FAutoConsoleVariableRef CVarUseTranslucentLightingVolumes( @@ -1075,6 +1077,8 @@ void FDeferredShadingSceneRenderer::ClearTranslucentVolumeLighting(FRHICommandLi if (GUseTranslucentLightingVolumes && GSupportsVolumeTextureRendering) { SCOPED_DRAW_EVENT(RHICmdList, ClearTranslucentVolumeLighting); + SCOPED_GPU_STAT(RHICmdList, Stat_GPU_TranslucentLighting); + FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList); // to track down Jira UE-22073 @@ -1292,6 +1296,7 @@ void FDeferredShadingSceneRenderer::InjectAmbientCubemapTranslucentVolumeLightin ensure(SceneContext.GetCurrentFeatureLevel() >= ERHIFeatureLevel::SM4); SCOPED_DRAW_EVENT(RHICmdList, InjectAmbientCubemapTranslucentVolumeLighting); + SCOPED_GPU_STAT(RHICmdList, Stat_GPU_TranslucentLighting); const FVolumeBounds VolumeBounds(GTranslucencyLightingVolumeDim); @@ -1351,6 +1356,7 @@ void FDeferredShadingSceneRenderer::ClearTranslucentVolumePerObjectShadowing(FRH { FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList); SCOPED_DRAW_EVENT(RHICmdList, ClearTranslucentVolumePerLightShadowing); + SCOPED_GPU_STAT(RHICmdList, Stat_GPU_TranslucentLighting); static_assert(TVC_MAX == 2, "Only expecting two translucency lighting cascades."); FTextureRHIParamRef RenderTargets[2]; @@ -1406,6 +1412,7 @@ void FDeferredShadingSceneRenderer::AccumulateTranslucentVolumeObjectShadowing(F if (GUseTranslucentLightingVolumes && GSupportsVolumeTextureRendering) { SCOPED_DRAW_EVENT(RHICmdList, AccumulateTranslucentVolumeShadowing); + SCOPED_GPU_STAT(RHICmdList, Stat_GPU_TranslucentLighting); auto ShaderMap = GetGlobalShaderMap(FeatureLevel); @@ -1952,6 +1959,8 @@ void FDeferredShadingSceneRenderer::FilterTranslucentVolumeLighting(FRHICommandL SCOPED_DRAW_EVENTF(RHICmdList, FilterTranslucentVolume, TEXT("FilterTranslucentVolume %dx%dx%d Cascades:%d"), GTranslucencyLightingVolumeDim, GTranslucencyLightingVolumeDim, GTranslucencyLightingVolumeDim, TVC_MAX); + SCOPED_GPU_STAT(RHICmdList, Stat_GPU_TranslucentLighting); + // Filter each cascade for (int32 VolumeCascadeIndex = 0; VolumeCascadeIndex < TVC_MAX; VolumeCascadeIndex++) { diff --git a/Engine/Source/Runtime/Renderer/Private/TranslucentRendering.cpp b/Engine/Source/Runtime/Renderer/Private/TranslucentRendering.cpp index 64fca144cbcf..93e3a9d3937f 100644 --- a/Engine/Source/Runtime/Renderer/Private/TranslucentRendering.cpp +++ b/Engine/Source/Runtime/Renderer/Private/TranslucentRendering.cpp @@ -16,6 +16,9 @@ DECLARE_CYCLE_STAT(TEXT("TranslucencyTimestampQuery Wait"), STAT_TranslucencyTim DECLARE_FLOAT_COUNTER_STAT(TEXT("Translucency GPU Time (MS)"), STAT_TranslucencyGPU, STATGROUP_SceneRendering); +DECLARE_FLOAT_COUNTER_STAT(TEXT("Translucency"), Stat_GPU_Translucency, STATGROUP_GPU); + + static TAutoConsoleVariable CVarSeparateTranslucencyAutoDownsample( TEXT("r.SeparateTranslucencyAutoDownsample"), 0, @@ -1177,6 +1180,7 @@ void FDeferredShadingSceneRenderer::RenderTranslucency(FRHICommandListImmediate& if (ShouldRenderTranslucency()) { SCOPED_DRAW_EVENT(RHICmdList, Translucency); + SCOPED_GPU_STAT(RHICmdList, Stat_GPU_Translucency); if (GRHICommandList.UseParallelAlgorithms() && CVarParallelTranslucency.GetValueOnRenderThread()) { diff --git a/Engine/Source/Runtime/Renderer/Private/VelocityRendering.cpp b/Engine/Source/Runtime/Renderer/Private/VelocityRendering.cpp index eb5ed90eb630..b00938cc0cd8 100644 --- a/Engine/Source/Runtime/Renderer/Private/VelocityRendering.cpp +++ b/Engine/Source/Runtime/Renderer/Private/VelocityRendering.cpp @@ -28,6 +28,8 @@ static TAutoConsoleVariable CVarRHICmdVelocityPassDeferredContexts( 1, TEXT("True to use deferred contexts to parallelize velocity pass command list execution.")); +DECLARE_FLOAT_COUNTER_STAT(TEXT("Render Velocities"), Stat_GPU_RenderVelocities, STATGROUP_GPU); + bool IsParallelVelocity() { return GRHICommandList.UseParallelAlgorithms() && CVarParallelVelocity.GetValueOnRenderThread(); @@ -849,6 +851,7 @@ void FDeferredShadingSceneRenderer::RenderVelocities(FRHICommandListImmediate& R check(!Views[0].bIsSceneCapture); SCOPED_DRAW_EVENT(RHICmdList, RenderVelocities); + SCOPED_GPU_STAT(RHICmdList, Stat_GPU_RenderVelocities); FPooledRenderTargetDesc Desc = FVelocityRendering::GetRenderTargetDesc(); GRenderTargetPool.FindFreeElement(RHICmdList, Desc, VelocityRT, TEXT("Velocity")); diff --git a/Engine/Source/Runtime/Renderer/Public/RendererInterface.h b/Engine/Source/Runtime/Renderer/Public/RendererInterface.h index 8227f442f4b8..e3a9191f3345 100644 --- a/Engine/Source/Runtime/Renderer/Public/RendererInterface.h +++ b/Engine/Source/Runtime/Renderer/Public/RendererInterface.h @@ -47,6 +47,7 @@ public: , bForceSeparateTargetAndShaderResource(false) , DebugName(TEXT("UnknownTexture")) , AutoWritable(true) + , bCreateRenderTargetWriteMask(false) { check(!IsValid()); } @@ -63,7 +64,8 @@ public: uint32 InTargetableFlags, bool bInForceSeparateTargetAndShaderResource, uint16 InNumMips = 1, - bool InAutowritable = true) + bool InAutowritable = true, + bool InCreateRTWriteMask = false) { check(InExtent.X); check(InExtent.Y); @@ -82,6 +84,7 @@ public: NewDesc.bForceSeparateTargetAndShaderResource = bInForceSeparateTargetAndShaderResource; NewDesc.DebugName = TEXT("UnknownTexture2D"); NewDesc.AutoWritable = InAutowritable; + NewDesc.bCreateRenderTargetWriteMask = InCreateRTWriteMask; check(NewDesc.Is2DTexture()); return NewDesc; } @@ -328,6 +331,8 @@ public: const TCHAR *DebugName; /** automatically set to writable via barrier during */ bool AutoWritable; + /** create render target write mask (supported only on specific platforms) */ + bool bCreateRenderTargetWriteMask; }; @@ -373,6 +378,9 @@ struct FSceneRenderTargetItem FUnorderedAccessViewRHIRef UAV; /** only created if requested through the flag */ TArray< FShaderResourceViewRHIRef > MipSRVs; + + FShaderResourceViewRHIRef RTWriteMaskBufferRHI_SRV; + FStructuredBufferRHIRef RTWriteMaskDataBufferRHI; }; /** diff --git a/Engine/Source/Runtime/Renderer/Public/SceneRenderTargetParameters.h b/Engine/Source/Runtime/Renderer/Public/SceneRenderTargetParameters.h index 8c96770add47..8837c788d2c8 100644 --- a/Engine/Source/Runtime/Renderer/Public/SceneRenderTargetParameters.h +++ b/Engine/Source/Runtime/Renderer/Public/SceneRenderTargetParameters.h @@ -86,6 +86,7 @@ private: FShaderResourceParameter ScreenSpaceAOTextureNonMS; FShaderResourceParameter CustomDepthTextureNonMS; FShaderResourceParameter DBufferATexture; + FShaderResourceParameter DBufferRenderMask; FShaderResourceParameter DBufferATextureSampler; FShaderResourceParameter DBufferBTexture; FShaderResourceParameter DBufferBTextureSampler; diff --git a/Engine/Source/Runtime/ShaderCore/Private/ShaderCore.cpp b/Engine/Source/Runtime/ShaderCore/Private/ShaderCore.cpp index eca6d9aa79e1..17e6e69f1cf8 100644 --- a/Engine/Source/Runtime/ShaderCore/Private/ShaderCore.cpp +++ b/Engine/Source/Runtime/ShaderCore/Private/ShaderCore.cpp @@ -434,7 +434,10 @@ void GetShaderIncludes(const TCHAR* Filename, TArray& IncludeFilenames, // Some headers aren't required to be found (platforms that the user doesn't have access to) // @todo: Is there some way to generalize this" - const bool bIsOptionalInclude = (ExtractedIncludeFilename == TEXT("PS4/PS4Common.usf") || ExtractedIncludeFilename == TEXT("PS4/PostProcessHMDMorpheus.usf")); + const bool bIsOptionalInclude = (ExtractedIncludeFilename == TEXT("PS4/PS4Common.usf") + || ExtractedIncludeFilename == TEXT("PS4/PostProcessHMDMorpheus.usf") + || ExtractedIncludeFilename == TEXT("PS4/RTWriteMaskProcessing.usf") + ); // ignore the header if it's optional and doesn't exist if (bIsOptionalInclude) { diff --git a/Engine/Source/Runtime/ShaderCore/Public/CrossCompilerCommon.h b/Engine/Source/Runtime/ShaderCore/Public/CrossCompilerCommon.h index 6621724414f2..963fb32f6914 100644 --- a/Engine/Source/Runtime/ShaderCore/Public/CrossCompilerCommon.h +++ b/Engine/Source/Runtime/ShaderCore/Public/CrossCompilerCommon.h @@ -37,6 +37,22 @@ namespace CrossCompiler PACKED_TYPEINDEX_MAX = 5, }; + static FORCEINLINE uint8 ShaderStageIndexToTypeName(uint8 ShaderStage) + { + switch (ShaderStage) + { + case SHADER_STAGE_VERTEX: return 'v'; + case SHADER_STAGE_PIXEL: return 'p'; + case SHADER_STAGE_GEOMETRY: return 'g'; + case SHADER_STAGE_HULL: return 'h'; + case SHADER_STAGE_DOMAIN: return 'd'; + case SHADER_STAGE_COMPUTE: return 'c'; + default: break; + } + check(0); + return 0; + } + static FORCEINLINE uint8 PackedTypeIndexToTypeName(uint8 ArrayType) { switch (ArrayType) diff --git a/Engine/Source/Runtime/SlateRHIRenderer/Private/SlateMaterialShader.cpp b/Engine/Source/Runtime/SlateRHIRenderer/Private/SlateMaterialShader.cpp index 9a82e8179a5d..4d0c364583a0 100644 --- a/Engine/Source/Runtime/SlateRHIRenderer/Private/SlateMaterialShader.cpp +++ b/Engine/Source/Runtime/SlateRHIRenderer/Private/SlateMaterialShader.cpp @@ -108,6 +108,10 @@ void FSlateMaterialShaderPS::SetParameters(FRHICommandList& RHICmdList, const FS // Modulate with the existing scene color RHICmdList.SetBlendState(TStaticBlendState::GetRHI()); break; + case BLEND_AlphaComposite: + // Blend with existing scene color. New color is already pre-multiplied by alpha. + RHICmdList.SetBlendState(TStaticBlendState::GetRHI()); + break; }; SetShaderValue( RHICmdList, ShaderRHI, ShaderParams, InShaderParams ); diff --git a/Engine/Source/Runtime/SlateRHIRenderer/Private/SlateRHIRenderer.cpp b/Engine/Source/Runtime/SlateRHIRenderer/Private/SlateRHIRenderer.cpp index e189371a066b..0b6fd8cedd3b 100644 --- a/Engine/Source/Runtime/SlateRHIRenderer/Private/SlateRHIRenderer.cpp +++ b/Engine/Source/Runtime/SlateRHIRenderer/Private/SlateRHIRenderer.cpp @@ -16,6 +16,8 @@ DECLARE_CYCLE_STAT(TEXT("Slate RT: Create Batches"), STAT_SlateRTCreateBatches, DECLARE_CYCLE_STAT(TEXT("Slate RT: Fill Vertex & Index Buffers"), STAT_SlateRTFillVertexIndexBuffers, STATGROUP_Slate); DECLARE_CYCLE_STAT(TEXT("Slate RT: Draw Batches"), STAT_SlateRTDrawBatches, STATGROUP_Slate); +DECLARE_FLOAT_COUNTER_STAT(TEXT("Slate UI/present"), Stat_GPU_SlateUI, STATGROUP_GPU); + // Defines the maximum size that a slate viewport will create #define MAX_VIEWPORT_SIZE 16384 @@ -396,6 +398,7 @@ void FSlateRHIRenderer::OnWindowDestroyed( const TSharedRef& InWindow ) void FSlateRHIRenderer::DrawWindow_RenderThread(FRHICommandListImmediate& RHICmdList, const FViewportInfo& ViewportInfo, FSlateWindowElementList& WindowElementList, bool bLockToVsync, bool bClear) { SCOPED_DRAW_EVENT(RHICmdList, SlateUI); + //SCOPED_GPU_STAT(RHICmdList, Stat_GPU_SlateUI); // Disabled since this seems to be distorted by the present time // Should only be called by the rendering thread check(IsInRenderingThread()); diff --git a/Engine/Source/Runtime/VulkanRHI/Private/VulkanCommandWrappers.h b/Engine/Source/Runtime/VulkanRHI/Private/VulkanCommandWrappers.h index f217e39a8205..cfd058b7f5af 100644 --- a/Engine/Source/Runtime/VulkanRHI/Private/VulkanCommandWrappers.h +++ b/Engine/Source/Runtime/VulkanRHI/Private/VulkanCommandWrappers.h @@ -21,10 +21,10 @@ namespace VulkanRHI void DumpPhysicalDeviceProperties(VkPhysicalDeviceMemoryProperties* Properties); void DumpAllocateMemory(VkDevice Device, const VkMemoryAllocateInfo* AllocateInfo, VkDeviceMemory* Memory); void DumpMemoryRequirements(VkMemoryRequirements* MemoryRequirements); - void DumpBufferCreate(VkDevice Device, const VkBufferCreateInfo* CreateInfo, VkBuffer* Buffer); - void DumpBufferViewCreate(VkDevice Device, const VkBufferViewCreateInfo* CreateInfo, VkBufferView* BufferView); - void DumpImageCreate(VkDevice Device, const VkImageCreateInfo* CreateInfo, VkImage* Image); - void DumpImageViewCreate(VkDevice Device, const VkImageViewCreateInfo* CreateInfo, VkImageView* ImageView); + void DumpCreateBuffer(VkDevice Device, const VkBufferCreateInfo* CreateInfo, VkBuffer* Buffer); + void DumpCreateBufferView(VkDevice Device, const VkBufferViewCreateInfo* CreateInfo, VkBufferView* BufferView); + void DumpCreateImage(VkDevice Device, const VkImageCreateInfo* CreateInfo, VkImage* Image); + void DumpCreateImageView(VkDevice Device, const VkImageViewCreateInfo* CreateInfo, VkImageView* ImageView); void DumpFenceCreate(VkDevice Device, const VkFenceCreateInfo* CreateInfo, VkFence* Fence); void DumpFenceList(uint32 FenceCount, const VkFence* Fences); void DumpSemaphoreCreate(VkDevice Device, const VkSemaphoreCreateInfo* CreateInfo, VkSemaphore* Semaphore); @@ -73,10 +73,10 @@ namespace VulkanRHI #define DumpPhysicalDeviceProperties(x) #define DumpAllocateMemory(d, i, m) #define DumpMemoryRequirements(x) - #define DumpBufferCreate(d, i, b) - #define DumpBufferViewCreate(d, i, v) - #define DumpImageCreate(d, x, i) - #define DumpImageViewCreate(d, i, v) + #define DumpCreateBuffer(d, i, b) + #define DumpCreateBufferView(d, i, v) + #define DumpCreateImage(d, x, i) + #define DumpCreateImageView(d, i, v) #define DumpFenceCreate(d, x, f) #define DumpFenceList(c, p) #define DumpSemaphoreCreate(d, i, s) @@ -542,7 +542,7 @@ namespace VulkanRHI static FORCEINLINE_DEBUGGABLE VkResult vkCreateBuffer(VkDevice Device, const VkBufferCreateInfo* CreateInfo, const VkAllocationCallbacks* Allocator, VkBuffer* Buffer) { - DumpBufferCreate(Device, CreateInfo, Buffer); + DumpCreateBuffer(Device, CreateInfo, Buffer); VkResult Result = ::vkCreateBuffer(Device, CreateInfo, Allocator, Buffer); @@ -559,7 +559,7 @@ namespace VulkanRHI static FORCEINLINE_DEBUGGABLE VkResult vkCreateBufferView(VkDevice Device, const VkBufferViewCreateInfo* CreateInfo, const VkAllocationCallbacks* Allocator, VkBufferView* View) { - DumpBufferViewCreate(Device, CreateInfo, View); + DumpCreateBufferView(Device, CreateInfo, View); DevicePrintfBeginResult(Device, FString::Printf(TEXT("vkCreateBufferView(Info=%p, OutView=%p)"), CreateInfo, View)); VkResult Result = ::vkCreateBufferView(Device, CreateInfo, Allocator, View); @@ -577,7 +577,7 @@ namespace VulkanRHI static FORCEINLINE_DEBUGGABLE VkResult vkCreateImage(VkDevice Device, const VkImageCreateInfo* CreateInfo, const VkAllocationCallbacks* Allocator, VkImage* Image) { - DumpImageCreate(Device, CreateInfo, Image); + DumpCreateImage(Device, CreateInfo, Image); VkResult Result = ::vkCreateImage(Device, CreateInfo, Allocator, Image); @@ -603,7 +603,7 @@ namespace VulkanRHI static FORCEINLINE_DEBUGGABLE VkResult vkCreateImageView(VkDevice Device, const VkImageViewCreateInfo* CreateInfo, const VkAllocationCallbacks* Allocator, VkImageView* View) { - DumpImageViewCreate(Device, CreateInfo, View); + DumpCreateImageView(Device, CreateInfo, View); VkResult Result = ::vkCreateImageView(Device, CreateInfo, Allocator, View); diff --git a/Engine/Source/Runtime/VulkanRHI/Private/VulkanCommands.cpp b/Engine/Source/Runtime/VulkanRHI/Private/VulkanCommands.cpp index bfa7f8af1ff3..a8e11bd93fbb 100644 --- a/Engine/Source/Runtime/VulkanRHI/Private/VulkanCommands.cpp +++ b/Engine/Source/Runtime/VulkanRHI/Private/VulkanCommands.cpp @@ -511,7 +511,7 @@ void FVulkanCommandListContext::RHIDrawPrimitive(uint32 PrimitiveType, uint32 Ba FVulkanCmdBuffer* CmdBuffer = CommandBufferManager->GetActiveCmdBuffer(); PendingState->PrepareDraw(this, CmdBuffer, UEToVulkanType((EPrimitiveType)PrimitiveType)); - NumInstances = FMath::Min(1U, NumInstances); + NumInstances = FMath::Max(1U, NumInstances); VulkanRHI::vkCmdDraw(CmdBuffer->GetHandle(), NumVertices, NumInstances, BaseVertexIndex, 0); //if (IsImmediate()) @@ -556,10 +556,10 @@ void FVulkanCommandListContext::RHIDrawIndexedPrimitive(FIndexBufferRHIParamRef VulkanRHI::vkCmdBindIndexBuffer(CmdBuffer, IndexBuffer->GetHandle(), IndexBuffer->GetOffset(), IndexBuffer->GetIndexType()); uint32 NumIndices = GetVertexCountForPrimitiveCount(NumPrimitives, PrimitiveType); - NumInstances = FMath::Min(1U, NumInstances); + NumInstances = FMath::Max(1U, NumInstances); VulkanRHI::vkCmdDrawIndexed(CmdBuffer, NumIndices, NumInstances, StartIndex, BaseVertexIndex, FirstInstance); - //if (IsImmediate()) + if (IsImmediate()) { VulkanRHI::GManager.GPUProfilingData.RegisterGPUWork(NumPrimitives * NumInstances, NumVertices * NumInstances); } @@ -583,7 +583,7 @@ void FVulkanCommandListContext::RHIDrawIndexedIndirect(FIndexBufferRHIParamRef I #endif VULKAN_SIGNAL_UNIMPLEMENTED(); - //if (IsImmediate()) + if (IsImmediate()) { VulkanRHI::GManager.GPUProfilingData.RegisterGPUWork(0); } @@ -606,7 +606,7 @@ void FVulkanCommandListContext::RHIDrawIndexedPrimitiveIndirect(uint32 Primitive #endif VULKAN_SIGNAL_UNIMPLEMENTED(); - //if (IsImmediate()) + if (IsImmediate()) { VulkanRHI::GManager.GPUProfilingData.RegisterGPUWork(0); } @@ -643,7 +643,7 @@ void FVulkanCommandListContext::RHIEndDrawPrimitiveUP() PendingState->PrepareDraw(this, CmdBuffer, UEToVulkanType((EPrimitiveType)PendingPrimitiveType)); VulkanRHI::vkCmdDraw(CmdBuffer->GetHandle(), PendingNumVertices, 1, PendingMinVertexIndex, 0); - //if (IsImmediate()) + if (IsImmediate()) { VulkanRHI::GManager.GPUProfilingData.RegisterGPUWork(PendingNumPrimitives, PendingNumVertices); } @@ -688,7 +688,7 @@ void FVulkanCommandListContext::RHIEndDrawIndexedPrimitiveUP() VulkanRHI::vkCmdBindIndexBuffer(Cmd, PendingDrawPrimUPIndexAllocInfo.GetHandle(), PendingDrawPrimUPIndexAllocInfo.GetBindOffset(), PendingPrimitiveIndexType); VulkanRHI::vkCmdDrawIndexed(Cmd, NumIndices, 1, PendingMinVertexIndex, 0, 0); - //if (IsImmediate()) + if (IsImmediate()) { VulkanRHI::GManager.GPUProfilingData.RegisterGPUWork(PendingNumPrimitives, PendingNumVertices); } @@ -721,7 +721,7 @@ void FVulkanCommandListContext::RHIClearMRT(bool bClearColor, int32 NumClearColo PendingState->UpdateRenderPass(CmdBuffer); const uint32 NumColorAttachments = PendingState->GetFrameBuffer()->GetNumColorAttachments(); - check((uint32)NumClearColors <= NumColorAttachments); + check(!bClearColor || (uint32)NumClearColors <= NumColorAttachments); InternalClearMRT(CmdBuffer, bClearColor, NumClearColors, ClearColorArray, bClearDepth, Depth, bClearStencil, Stencil, ExcludeRect); } diff --git a/Engine/Source/Runtime/VulkanRHI/Private/VulkanDebug.cpp b/Engine/Source/Runtime/VulkanRHI/Private/VulkanDebug.cpp index 2903f84c89a8..e8219c8b51c8 100644 --- a/Engine/Source/Runtime/VulkanRHI/Private/VulkanDebug.cpp +++ b/Engine/Source/Runtime/VulkanRHI/Private/VulkanDebug.cpp @@ -1,855 +1,1231 @@ -// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved. - -/*============================================================================= - VulkanDebug.cpp: Vulkan device RHI implementation. -=============================================================================*/ - -#include "VulkanRHIPrivate.h" - -#if VK_HEADER_VERSION < 8 && (VK_API_VERSION < VK_MAKE_VERSION(1, 0, 3)) -#include -#endif - -#define VULKAN_ENABLE_API_DUMP_DETAILED 0 - -#define CREATE_MSG_CALLBACK "vkCreateDebugReportCallbackEXT" -#define DESTROY_MSG_CALLBACK "vkDestroyDebugReportCallbackEXT" - -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* 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) - { - ensure(0); - } - - 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(LayerPrefix), MsgCode); - static TSet SeenCodes; - if (!SeenCodes.Contains(LayerCode)) - { -#if VULKAN_ENABLE_DUMP_LAYER - VulkanRHI::FlushDebugWrapperLog(); -#endif - FString Message = FString::Printf(TEXT("VK ERROR: [%s] Code %d : %s"), ANSI_TO_TCHAR(LayerPrefix), MsgCode, ANSI_TO_TCHAR(Msg)); - FPlatformMisc::LowLevelOutputDebugStringf(TEXT("VulkanRHI: %s\n"), *Message); - UE_LOG(LogVulkanRHI, Error, TEXT("%s"), *Message); - -#if UE_BUILD_DEBUG || UE_BUILD_DEVELOPMENT - //if (!FCStringAnsi::Strcmp(LayerPrefix, "MEM")) - { - //((FVulkanDynamicRHI*)GDynamicRHI)->DumpMemory(); - } -#endif - - // Break debugger on first instance of each message. - // Continuing will ignore the error and suppress this message in future. - bool bIgnoreInFuture = true; - ensureAlways(0); - if (bIgnoreInFuture) - { - SeenCodes.Add(LayerCode); - } - } - return VK_FALSE; - } - else if (MsgFlags & VK_DEBUG_REPORT_WARNING_BIT_EXT) - { -#if VULKAN_ENABLE_DUMP_LAYER - VulkanRHI::FlushDebugWrapperLog(); -#endif - FString Message = FString::Printf(TEXT("VK WARNING: [%s] Code %d : %s\n"), ANSI_TO_TCHAR(LayerPrefix), MsgCode, ANSI_TO_TCHAR(Msg)); - FPlatformMisc::LowLevelOutputDebugStringf(TEXT("VulkanRHI: %s\n"), *Message); - UE_LOG(LogVulkanRHI, Warning, TEXT("%s"), *Message); - return VK_FALSE; - } -#if VULKAN_ENABLE_API_DUMP - else if (MsgFlags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) - { -#if !VULKAN_ENABLE_API_DUMP_DETAILED - if (!FCStringAnsi::Strcmp(LayerPrefix, "MEM") || !FCStringAnsi::Strcmp(LayerPrefix, "DS")) - { - // Skip Mem messages - } - else -#endif - { - FString Message = FString::Printf(TEXT("VK INFO: [%s] Code %d : %s\n"), ANSI_TO_TCHAR(LayerPrefix), MsgCode, ANSI_TO_TCHAR(Msg)); - FPlatformMisc::LowLevelOutputDebugStringf(TEXT("VulkanRHI: %s\n"), *Message); - UE_LOG(LogVulkanRHI, Display, TEXT("%s"), *Message); - } - - return VK_FALSE; - } -#if VULKAN_ENABLE_API_DUMP_DETAILED - else if (MsgFlags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) - { - FString Message = FString::Printf(TEXT("VK DEBUG: [%s] Code %d : %s\n"), ANSI_TO_TCHAR(LayerPrefix), MsgCode, ANSI_TO_TCHAR(Msg)); - FPlatformMisc::LowLevelOutputDebugStringf(TEXT("VulkanRHI: %s\n"), *Message); - UE_LOG(LogVulkanRHI, Display, TEXT("%s"), *Message); - return VK_FALSE; - } -#endif -#endif - - return VK_TRUE; -} - -void FVulkanDynamicRHI::SetupDebugLayerCallback() -{ -#if !VULKAN_DISABLE_DEBUG_CALLBACK - PFN_vkCreateDebugReportCallbackEXT CreateMsgCallback = (PFN_vkCreateDebugReportCallbackEXT)(void*)VulkanRHI::vkGetInstanceProcAddr(Instance, CREATE_MSG_CALLBACK); - if (CreateMsgCallback) - { - VkDebugReportCallbackCreateInfoEXT CreateInfo; - FMemory::Memzero(CreateInfo); - CreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT; - CreateInfo.pfnCallback = DebugReportFunction; - CreateInfo.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT; -#if VULKAN_ENABLE_API_DUMP - CreateInfo.flags |= VK_DEBUG_REPORT_INFORMATION_BIT_EXT; -#if VULKAN_ENABLE_API_DUMP_DETAILED - CreateInfo.flags |= VK_DEBUG_REPORT_DEBUG_BIT_EXT; -#endif -#endif - VkResult Result = CreateMsgCallback(Instance, &CreateInfo, nullptr, &MsgCallback); - switch (Result) - { - case VK_SUCCESS: - break; - case VK_ERROR_OUT_OF_HOST_MEMORY: - UE_LOG(LogVulkanRHI, Warning, TEXT("CreateMsgCallback: out of host memory/CreateMsgCallback Failure; debug reporting skipped")); - break; - default: - UE_LOG(LogVulkanRHI, Warning, TEXT("CreateMsgCallback: unknown failure %d/CreateMsgCallback Failure; debug reporting skipped"), (int32)Result); - break; - } - } - else - { - UE_LOG(LogVulkanRHI, Warning, TEXT("GetProcAddr: Unable to find vkDbgCreateMsgCallback/vkGetInstanceProcAddr; debug reporting skipped!")); - } -#endif -} - -void FVulkanDynamicRHI::RemoveDebugLayerCallback() -{ -#if !VULKAN_DISABLE_DEBUG_CALLBACK - if (MsgCallback != VK_NULL_HANDLE) - { - PFN_vkDestroyDebugReportCallbackEXT DestroyMsgCallback = (PFN_vkDestroyDebugReportCallbackEXT)(void*)VulkanRHI::vkGetInstanceProcAddr(Instance, DESTROY_MSG_CALLBACK); - checkf(DestroyMsgCallback, TEXT("GetProcAddr: Unable to find vkDbgCreateMsgCallback\vkGetInstanceProcAddr Failure")); - DestroyMsgCallback(Instance, MsgCallback, nullptr); - } -#endif -} - - -#if VULKAN_ENABLE_DUMP_LAYER -namespace VulkanRHI -{ - static FString DebugLog; - static int32 DebugLine = 1; - - static const TCHAR* Tabs = TEXT("\t\t\t\t\t\t\t\t\t"); - - void FlushDebugWrapperLog() - { - if (DebugLog.Len() > 0) - { - GLog->Flush(); - UE_LOG(LogVulkanRHI, Display, TEXT("Vulkan Wrapper Log:\n%s"), *DebugLog); - GLog->Flush(); - DebugLog = TEXT(""); - } - } - - static void HandleFlushWrapperLog(const TArray& Args) - { - FlushDebugWrapperLog(); - } - - static FAutoConsoleCommand CVarVulkanFlushLog( - TEXT("r.Vulkan.FlushLog"), - TEXT("\n"), - FConsoleCommandWithArgsDelegate::CreateStatic(&HandleFlushWrapperLog) - ); - - static TAutoConsoleVariable CVarVulkanDumpLayer( - TEXT("r.Vulkan.DumpLayer"), - 0, - TEXT("1 to enable dump layer, 0 to disable (default)") - ); - - static FString GetVkResultErrorString(VkResult Result) - { - FString ErrorString; - switch (Result) - { -#define VKSWITCHCASE(x) case x: ErrorString = TEXT(#x); break; - VKSWITCHCASE(VK_SUCCESS) - VKSWITCHCASE(VK_NOT_READY) - VKSWITCHCASE(VK_TIMEOUT) - VKSWITCHCASE(VK_EVENT_SET) - VKSWITCHCASE(VK_EVENT_RESET) - VKSWITCHCASE(VK_INCOMPLETE) - VKSWITCHCASE(VK_ERROR_OUT_OF_HOST_MEMORY) - VKSWITCHCASE(VK_ERROR_OUT_OF_DEVICE_MEMORY) - VKSWITCHCASE(VK_ERROR_INITIALIZATION_FAILED) - VKSWITCHCASE(VK_ERROR_DEVICE_LOST) - VKSWITCHCASE(VK_ERROR_MEMORY_MAP_FAILED) - VKSWITCHCASE(VK_ERROR_LAYER_NOT_PRESENT) - VKSWITCHCASE(VK_ERROR_EXTENSION_NOT_PRESENT) - VKSWITCHCASE(VK_ERROR_FEATURE_NOT_PRESENT) - VKSWITCHCASE(VK_ERROR_INCOMPATIBLE_DRIVER) - VKSWITCHCASE(VK_ERROR_TOO_MANY_OBJECTS) - VKSWITCHCASE(VK_ERROR_FORMAT_NOT_SUPPORTED) - VKSWITCHCASE(VK_ERROR_SURFACE_LOST_KHR) - VKSWITCHCASE(VK_ERROR_NATIVE_WINDOW_IN_USE_KHR) - VKSWITCHCASE(VK_SUBOPTIMAL_KHR) - VKSWITCHCASE(VK_ERROR_OUT_OF_DATE_KHR) - VKSWITCHCASE(VK_ERROR_INCOMPATIBLE_DISPLAY_KHR) - VKSWITCHCASE(VK_ERROR_VALIDATION_FAILED_EXT) - VKSWITCHCASE(VK_ERROR_INVALID_SHADER_NV) -#undef VKSWITCHCASE - default: - ErrorString = FString::Printf(TEXT("Unknown VkResult %d"), (int32)Result); - break; - } - - return ErrorString; - } - - static FString GetImageLayoutString(VkImageLayout Layout) - { - FString String; - switch (Layout) - { -#define VKSWITCHCASE(x) case x: String = TEXT(#x); break; - VKSWITCHCASE(VK_IMAGE_LAYOUT_UNDEFINED) - VKSWITCHCASE(VK_IMAGE_LAYOUT_GENERAL) - VKSWITCHCASE(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) - VKSWITCHCASE(VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) - VKSWITCHCASE(VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL) - VKSWITCHCASE(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) - VKSWITCHCASE(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) - VKSWITCHCASE(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) - VKSWITCHCASE(VK_IMAGE_LAYOUT_PREINITIALIZED) - VKSWITCHCASE(VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) -#undef VKSWITCHCASE - default: - String = FString::Printf(TEXT("Unknown VkImageLayout %d"), (int32)Layout); - break; - } - - return String; - } - - static FString GetComponentMappingString(const VkComponentMapping& Mapping) - { - auto GetSwizzle = [](VkComponentSwizzle Swizzle) -> const TCHAR* - { - switch (Swizzle) - { - case VK_COMPONENT_SWIZZLE_IDENTITY: return TEXT("ID"); - case VK_COMPONENT_SWIZZLE_ZERO: return TEXT("0"); - case VK_COMPONENT_SWIZZLE_ONE: return TEXT("1"); - case VK_COMPONENT_SWIZZLE_R: return TEXT("R"); - case VK_COMPONENT_SWIZZLE_G: return TEXT("G"); - case VK_COMPONENT_SWIZZLE_B: return TEXT("B"); - case VK_COMPONENT_SWIZZLE_A: return TEXT("A"); - default: - check(0); - return TEXT("-"); - } - }; - return FString::Printf(TEXT("(r=%s, g=%s, b=%s, a=%s)"), GetSwizzle(Mapping.r), GetSwizzle(Mapping.g), GetSwizzle(Mapping.b), GetSwizzle(Mapping.a)); - } - - -#define AppendBitFieldName(BitField, Name) \ - if ((Flags & BitField) == BitField)\ - {\ - Flags &= ~BitField;\ - String += Name;\ - if (bFirst)\ - {\ - bFirst = false;\ - }\ - else\ - {\ - if (Flags !=0)\ - {\ - String += TEXT("|");\ - }\ - }\ - } - - static FString GetAspectMaskString(VkImageAspectFlags Flags) - { - if (Flags == 0) - { - return TEXT("0"); - } - bool bFirst = true; - FString String; - AppendBitFieldName(VK_IMAGE_ASPECT_COLOR_BIT, TEXT("COLOR")); - AppendBitFieldName(VK_IMAGE_ASPECT_DEPTH_BIT, TEXT("DEPTH")); - AppendBitFieldName(VK_IMAGE_ASPECT_STENCIL_BIT, TEXT("STENCIL")); - AppendBitFieldName(VK_IMAGE_ASPECT_METADATA_BIT, TEXT("METADATA")); - if (Flags != 0) - { - FString Unknown = FString::Printf(TEXT("%d"), Flags); - AppendBitFieldName(Flags, Unknown); - } - return String; - } - - static FString GetAccessFlagString(VkAccessFlags Flags) - { - if (Flags == 0) - { - return TEXT("0"); - } - bool bFirst = true; - FString String; - AppendBitFieldName(VK_ACCESS_INDIRECT_COMMAND_READ_BIT, TEXT("INDIRECT_COMMAND")); - AppendBitFieldName(VK_ACCESS_INDEX_READ_BIT, TEXT("INDEX_READ")); - AppendBitFieldName(VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT, TEXT("VERTEX_ATTR_READ")); - AppendBitFieldName(VK_ACCESS_UNIFORM_READ_BIT, TEXT("UNIF_READ")); - AppendBitFieldName(VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, TEXT("INPUT_ATT_READ")); - AppendBitFieldName(VK_ACCESS_SHADER_READ_BIT, TEXT("SHADER_READ")); - AppendBitFieldName(VK_ACCESS_SHADER_WRITE_BIT, TEXT("SHADER_WRITE")); - AppendBitFieldName(VK_ACCESS_COLOR_ATTACHMENT_READ_BIT, TEXT("COLOR_ATT_READ")); - AppendBitFieldName(VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, TEXT("COLOR_ATT_WRITE")); - AppendBitFieldName(VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT, TEXT("DS_ATT_READ")); - AppendBitFieldName(VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, TEXT("DS_ATT_WIRTE")); - AppendBitFieldName(VK_ACCESS_TRANSFER_READ_BIT, TEXT("TRANSFER_READ")); - AppendBitFieldName(VK_ACCESS_TRANSFER_WRITE_BIT, TEXT("TRANSFER_WRITE")); - AppendBitFieldName(VK_ACCESS_HOST_READ_BIT, TEXT("HOST_READ")); - AppendBitFieldName(VK_ACCESS_HOST_WRITE_BIT, TEXT("HOST_WRITE")); - AppendBitFieldName(VK_ACCESS_MEMORY_READ_BIT, TEXT("MEM_READ")); - AppendBitFieldName(VK_ACCESS_MEMORY_WRITE_BIT, TEXT("MEM_WRITE")); - if (Flags != 0) - { - FString Unknown = FString::Printf(TEXT("%d"), Flags); - AppendBitFieldName(Flags, Unknown); - } - return String; - } - -#undef AppendBitFieldName - - static FString GetSubResourceRangeString(const VkImageSubresourceRange& Range) - { - return FString::Printf(TEXT("aspectMask=%s, baseMipLevel=%d, levelCount=%d, baseArrayLayer=%d, layerCount=%d"), *GetAspectMaskString(Range.aspectMask), Range.baseMipLevel, Range.levelCount, Range.baseArrayLayer, Range.layerCount); - } - - static FString GetStageMaskString(VkPipelineStageFlags Flags) - { - return FString::Printf(TEXT("VkPipelineStageFlags=0x%x"), (uint32)Flags); - } - - void PrintfBeginResult(const FString& String) - { - if (CVarVulkanDumpLayer.GetValueOnAnyThread()) - { - DebugLog += FString::Printf(TEXT("[GLOBAL METHOD] %8d: %s"), DebugLine++, *String); - } - } - - void PrintfBegin(const FString& String) - { - if (CVarVulkanDumpLayer.GetValueOnAnyThread()) - { - DebugLog += FString::Printf(TEXT("[GLOBAL METHOD] %8d: %s\n"), DebugLine++, *String); - } - } - - void DevicePrintfBeginResult(VkDevice Device, const FString& String) - { - if (CVarVulkanDumpLayer.GetValueOnAnyThread()) - { - DebugLog += FString::Printf(TEXT("[D:%p]%8d: %s"), Device, DebugLine++, *String); - } - } - - void DevicePrintfBegin(VkDevice Device, const FString& String) - { - if (CVarVulkanDumpLayer.GetValueOnAnyThread()) - { - DebugLog += FString::Printf(TEXT("[D:%p]%8d: %s\n"), Device, DebugLine++, *String); - } - } - - void CmdPrintfBegin(VkCommandBuffer CmdBuffer, const FString& String) - { - if (CVarVulkanDumpLayer.GetValueOnAnyThread()) - { - DebugLog += FString::Printf(TEXT("[C:%p]%8d: %s\n"), CmdBuffer, DebugLine++, *String); - } - } - - void CmdPrintfBeginResult(VkCommandBuffer CmdBuffer, const FString& String) - { - if (CVarVulkanDumpLayer.GetValueOnAnyThread()) - { - DebugLog += FString::Printf(TEXT("[C:%p]%8d: %s"), CmdBuffer, DebugLine++, *String); - } - } - - void PrintResult(VkResult Result) - { - if (CVarVulkanDumpLayer.GetValueOnAnyThread()) - { - DebugLog += FString::Printf(TEXT(" -> %s\n"), *GetVkResultErrorString(Result)); - if (Result < VK_SUCCESS) - { - FlushDebugWrapperLog(); - } - } - } - - void PrintResultAndPointer(VkResult Result, void* Handle) - { - if (CVarVulkanDumpLayer.GetValueOnAnyThread()) - { - DebugLog += FString::Printf(TEXT(" -> %s => %p\n"), *GetVkResultErrorString(Result), Handle); - if (Result < VK_SUCCESS) - { - FlushDebugWrapperLog(); - } - } - } - - void PrintResultAndNamedHandle(VkResult Result, const TCHAR* HandleName, void* Handle) - { - if (CVarVulkanDumpLayer.GetValueOnAnyThread()) - { - DebugLog += FString::Printf(TEXT(" -> %s => %s=%p\n"), *GetVkResultErrorString(Result), HandleName, Handle); - if (Result < VK_SUCCESS) - { - FlushDebugWrapperLog(); - } - } - } - - void DumpPhysicalDeviceProperties(VkPhysicalDeviceMemoryProperties* Properties) - { - if (CVarVulkanDumpLayer.GetValueOnAnyThread()) - { - DebugLog += FString::Printf(TEXT(" -> VkPhysicalDeviceMemoryProperties[...]\n")); - } - } - - void DumpAllocateMemory(VkDevice Device, const VkMemoryAllocateInfo* AllocateInfo, VkDeviceMemory* Memory) - { - if (CVarVulkanDumpLayer.GetValueOnAnyThread()) - { - DevicePrintfBeginResult(Device, FString::Printf(TEXT("vkAllocateMemory(OutMem=%p)\n"), AllocateInfo, Memory)); - DebugLog += Tabs; - DebugLog += FString::Printf(TEXT("VkMemoryAllocateInfo %p: Size=%d, MemoryTypeIndex=%d"), AllocateInfo, (uint32)AllocateInfo->allocationSize, AllocateInfo->memoryTypeIndex); - } - } - - void DumpMemoryRequirements(VkMemoryRequirements* MemoryRequirements) - { - if (CVarVulkanDumpLayer.GetValueOnAnyThread()) - { - DebugLog += FString::Printf(TEXT(" -> Size=%d Align=%d MemoryTypeBits=0x%x\n"), (uint32)MemoryRequirements->size, (uint32)MemoryRequirements->alignment, MemoryRequirements->memoryTypeBits); - } - } - - void DumpBufferCreate(VkDevice Device, const VkBufferCreateInfo* CreateInfo, VkBuffer* Buffer) - { - FlushDebugWrapperLog(); - DevicePrintfBeginResult(Device, FString::Printf(TEXT("vkCreateBuffer(Info=%p, OutBuffer=%p)[...]"), CreateInfo, Buffer)); - } - - void DumpBufferViewCreate(VkDevice Device, const VkBufferViewCreateInfo* CreateInfo, VkBufferView* BufferView) - { - DevicePrintfBeginResult(Device, FString::Printf(TEXT("VkBufferViewCreateInfo(Info=%p, OutBufferView=%p)[...]"), CreateInfo, BufferView)); - } - - void DumpImageCreate(VkDevice Device, const VkImageCreateInfo* CreateInfo, VkImage* Image) - { - FlushDebugWrapperLog(); - DevicePrintfBeginResult(Device, FString::Printf(TEXT("vkCreateImage(Info=%p, OutImage=%p)[...]"), CreateInfo, Image)); - } - - void DumpImageViewCreate(VkDevice Device, const VkImageViewCreateInfo* CreateInfo, VkImageView* ImageView) - { - DevicePrintfBegin(Device, FString::Printf(TEXT("VkImageViewCreateInfo(Info=%p, OutImageView=%p)"), CreateInfo, ImageView)); - - if (CVarVulkanDumpLayer.GetValueOnAnyThread()) - { - DebugLog += FString::Printf(TEXT("%sVkImageViewCreateInfo: Flags=%d, Image=%p, ViewType=%d, Format=%p, Components=%s\n"), Tabs, CreateInfo->flags, CreateInfo->image, (int32)CreateInfo->viewType, (void*)CreateInfo->format, *GetComponentMappingString(CreateInfo->components)); - DebugLog += FString::Printf(TEXT("%s\tSubresourceRange=(%s)"), Tabs, *GetSubResourceRangeString(CreateInfo->subresourceRange)); - } - } - - void DumpFenceCreate(VkDevice Device, const VkFenceCreateInfo* CreateInfo, VkFence* Fence) - { - DevicePrintfBeginResult(Device, FString::Printf(TEXT("vkCreateFence(CreateInfo=%p, OutFence=%p)[...]"), CreateInfo, Fence)); - } - - void DumpFenceList(uint32 FenceCount, const VkFence* Fences) - { - if (CVarVulkanDumpLayer.GetValueOnAnyThread()) - { - for (uint32 Index = 0; Index < FenceCount; ++Index) - { - DebugLog += Tabs; - DebugLog += '\t'; - DebugLog += FString::Printf(TEXT("Fence[%d]=%p"), Index, Fences[Index]); - if (Index < FenceCount - 1) - { - DebugLog += TEXT("\n"); - } - } - } - } - - void DumpSemaphoreCreate(VkDevice Device, const VkSemaphoreCreateInfo* CreateInfo, VkSemaphore* Semaphore) - { - DevicePrintfBeginResult(Device, FString::Printf(TEXT("vkCreateSemaphore(CreateInfo=%p, OutSemaphore=%p)[...]"), CreateInfo, Semaphore)); - } - - void DumpMappedMemoryRanges(uint32 memoryRangeCount, const VkMappedMemoryRange* MemoryRanges) - { - ensure(0); - } - - void DumpResolveImage(VkCommandBuffer CommandBuffer, VkImage SrcImage, VkImageLayout SrcImageLayout, VkImage DstImage, VkImageLayout DstImageLayout, uint32 RegionCount, const VkImageResolve* Regions) - { - if (CVarVulkanDumpLayer.GetValueOnAnyThread()) - { - CmdPrintfBegin(CommandBuffer, FString::Printf(TEXT("vkCmdResolveImage(SrcImage=%p, SrcImageLayout=%s, DestImage=%p, DestImageLayout=%s, NumRegions=%d, Regions=%p)[...]"), - CommandBuffer, SrcImage, *GetImageLayoutString(SrcImageLayout), DstImage, *GetImageLayoutString(DstImageLayout), RegionCount, Regions)); - for (uint32 Index = 0; Index < RegionCount; ++Index) - { - DebugLog += Tabs; - DebugLog += FString::Printf(TEXT("Region %d: "), Index); - /* - typedef struct VkImageResolve { - VkImageSubresourceLayers srcSubresource; - VkOffset3D srcOffset; - VkImageSubresourceLayers dstSubresource; - VkOffset3D dstOffset; - VkExtent3D extent; - - */ - } - } - } - - void DumpFreeDescriptorSets(VkDevice Device, VkDescriptorPool DescriptorPool, uint32 DescriptorSetCount, const VkDescriptorSet* DescriptorSets) - { - if (CVarVulkanDumpLayer.GetValueOnAnyThread()) - { - DevicePrintfBegin(Device, FString::Printf(TEXT("vkFreeDescriptorSets(Pool=%p, NumSets=%d, Sets=%p)"), DescriptorPool, DescriptorSetCount, DescriptorSets)); - for (uint32 Index = 0; Index < DescriptorSetCount; ++Index) - { - DebugLog += Tabs; - DebugLog += FString::Printf(TEXT("Set %d: %p\n"), Index, DescriptorSets[Index]); - } - } - } - - void DumpCreateInstance(const VkInstanceCreateInfo* CreateInfo, VkInstance* Instance) - { - PrintfBegin(FString::Printf(TEXT("vkCreateInstance(Info=%p, OutInstance=%p)[...]"), CreateInfo, Instance)); - } - - void DumpEnumeratePhysicalDevicesEpilog(uint32* PhysicalDeviceCount, VkPhysicalDevice* PhysicalDevices) - { - if (CVarVulkanDumpLayer.GetValueOnAnyThread()) - { - if (PhysicalDeviceCount) - { - DebugLog += Tabs; - DebugLog += FString::Printf(TEXT("OutCount=%d\n"), *PhysicalDeviceCount); - if (PhysicalDevices) - { - for (uint32 Index = 0; Index < *PhysicalDeviceCount; ++Index) - { - DebugLog += Tabs; - DebugLog += FString::Printf(TEXT("\tOutDevice[%d]=%p\n"), Index, PhysicalDevices[Index]); - } - } - } - } - } - - void DumpCmdPipelineBarrier(VkCommandBuffer CommandBuffer, VkPipelineStageFlags SrcStageMask, VkPipelineStageFlags DstStageMask, VkDependencyFlags DependencyFlags, uint32 MemoryBarrierCount, const VkMemoryBarrier* MemoryBarriers, uint32 BufferMemoryBarrierCount, const VkBufferMemoryBarrier* BufferMemoryBarriers, uint32 ImageMemoryBarrierCount, const VkImageMemoryBarrier* ImageMemoryBarriers) - { - CmdPrintfBegin(CommandBuffer, FString::Printf(TEXT("vkCmdPipelineBarrier(SrcMask=%s, DestMask=%s, Flags=%d, NumMemB=%d, MemB=%p,"), *GetStageMaskString(SrcStageMask), *GetStageMaskString(DstStageMask), (uint32)DependencyFlags, MemoryBarrierCount, MemoryBarriers)); - if (CVarVulkanDumpLayer.GetValueOnAnyThread()) - { - DebugLog += FString::Printf(TEXT("%s\tNumBufferB=%d, BufferB=%p, NumImageB=%d, ImageB=%p)[...]\n"), Tabs, BufferMemoryBarrierCount, BufferMemoryBarriers, ImageMemoryBarrierCount, ImageMemoryBarriers); - if (ImageMemoryBarrierCount) - { - for (uint32 Index = 0; Index < ImageMemoryBarrierCount; ++Index) - { - DebugLog += FString::Printf(TEXT("%s\tImageBarrier[%d]: srcAccess=%s, oldLayout=%s, srcQueueFamilyIndex=%d\n"), Tabs, Index, *GetAccessFlagString(ImageMemoryBarriers[Index].srcAccessMask), *GetImageLayoutString(ImageMemoryBarriers[Index].oldLayout), ImageMemoryBarriers[Index].srcQueueFamilyIndex); - DebugLog += FString::Printf(TEXT("%s\t\tdstAccess=%s, newLayout=%s, dstQueueFamilyIndex=%d\n"), Tabs, *GetAccessFlagString(ImageMemoryBarriers[Index].dstAccessMask), *GetImageLayoutString(ImageMemoryBarriers[Index].newLayout), ImageMemoryBarriers[Index].dstQueueFamilyIndex); - DebugLog += FString::Printf(TEXT("%s\t\tImage=%p, subresourceRange=(%s)\n"), Tabs, ImageMemoryBarriers[Index].image, *GetSubResourceRangeString(ImageMemoryBarriers[Index].subresourceRange)); - } - } - } - } - - void DumpBindDescriptorSets(VkCommandBuffer CommandBuffer, VkPipelineBindPoint PipelineBindPoint, VkPipelineLayout Layout, uint32 FirstSet, uint32 DescriptorSetCount, const VkDescriptorSet* DescriptorSets, uint32 DynamicOffsetCount, const uint32* DynamicOffsets) - { - CmdPrintfBegin(CommandBuffer, FString::Printf(TEXT("vkCmdBindDescriptorSets(PipelineBindPoint=%d, Layout=%p, FirstSet=%d, NumDS=%d, DS=%p, NumDynamicOffset=%d, DynamicOffsets=%p)[...]"), (int32)PipelineBindPoint, Layout, FirstSet, DescriptorSetCount, DescriptorSets, DynamicOffsetCount, DynamicOffsets)); - if (CVarVulkanDumpLayer.GetValueOnAnyThread()) - { - for (uint32 Index = 0; Index < DescriptorSetCount; ++Index) - { - DebugLog += FString::Printf(TEXT("%s\tDS[%d]=%p\n"), Tabs, Index, DescriptorSets[Index]); - } - for (uint32 Index = 0; Index < DynamicOffsetCount; ++Index) - { - DebugLog += FString::Printf(TEXT("%s\tDynamicOffset[%d]=%p\n"), Tabs, Index, DynamicOffsets[Index]); - } - } - } - - void DumpCreateDescriptorSetLayout(VkDevice Device, const VkDescriptorSetLayoutCreateInfo* CreateInfo, VkDescriptorSetLayout* SetLayout) - { - DevicePrintfBegin(Device, FString::Printf(TEXT("vkCreateDescriptorSetLayout(Info=%p, OutLayout=%p)[...]"), CreateInfo, SetLayout)); - } - - void DumpAllocateDescriptorSets(VkDevice Device, const VkDescriptorSetAllocateInfo* AllocateInfo, VkDescriptorSet* DescriptorSets) - { - DevicePrintfBegin(Device, FString::Printf(TEXT("vkAllocateDescriptorSets(Info=%p, OutSets=%p)[...]"), AllocateInfo, DescriptorSets)); - } - - void DumpUpdateDescriptorSets(VkDevice Device, uint32 DescriptorWriteCount, const VkWriteDescriptorSet* DescriptorWrites, uint32 DescriptorCopyCount, const VkCopyDescriptorSet* DescriptorCopies) - { - DevicePrintfBegin(Device, FString::Printf(TEXT("vkUpdateDescriptorSets(NumWrites=%d, Writes=%p, NumCopies=%d, Copies=%p)[...]"), DescriptorWriteCount, DescriptorWrites, DescriptorCopyCount, DescriptorCopies)); - } - - void DumpCreateFramebuffer(VkDevice Device, const VkFramebufferCreateInfo* CreateInfo, VkFramebuffer* Framebuffer) - { - if (CVarVulkanDumpLayer.GetValueOnAnyThread()) - { - DevicePrintfBegin(Device, FString::Printf(TEXT("vkCreateFramebuffer(Info=%p, OutFramebuffer=%p)"), CreateInfo, Framebuffer)); - DebugLog += FString::Printf(TEXT("%sVkFramebufferCreateInfo: Flags=%d, RenderPass=%p, NumAttachments=%d\n"), Tabs, CreateInfo->flags, CreateInfo->renderPass, CreateInfo->attachmentCount); - for (uint32 Index = 0; Index < CreateInfo->attachmentCount; ++Index) - { - DebugLog += FString::Printf(TEXT("%s\tAttachment[%d]: ImageView=%p\n"), Tabs, Index, CreateInfo->pAttachments[Index]); - } - DebugLog += FString::Printf(TEXT("%s\twidth=%d, height=%d, layers=%d"), Tabs, CreateInfo->width, CreateInfo->height, CreateInfo->layers); - } - } - - void DumpCreateRenderPass(VkDevice Device, const VkRenderPassCreateInfo* CreateInfo, VkRenderPass* RenderPass) - { - DevicePrintfBeginResult(Device, FString::Printf(TEXT("vkCreateRenderPass(Info=%p, OutRenderPass=%p)[...]"), CreateInfo, RenderPass)); - } - - void DumpQueueSubmit(VkQueue Queue, uint32 SubmitCount, const VkSubmitInfo* Submits, VkFence Fence) - { - if (CVarVulkanDumpLayer.GetValueOnAnyThread()) - { - PrintfBeginResult(FString::Printf(TEXT("vkQueueSubmit(Queue=%p, Count=%d, Submits=%p, Fence=%p)"), Queue, SubmitCount, Submits, Fence)); - for (uint32 Index = 0; Index < SubmitCount; ++Index) - { - DebugLog += FString::Printf(TEXT("\n%sSubmit[%d]:"), Tabs, Index); - if (Submits[Index].waitSemaphoreCount > 0) - { - DebugLog += FString::Printf(TEXT("\n%s\tWaitSemaphores(Mask): "), Tabs, Index); - for (uint32 SubIndex = 0; SubIndex < Submits[Index].waitSemaphoreCount; ++SubIndex) - { - DebugLog += FString::Printf(TEXT("%p(%d) "), Submits[Index].pWaitSemaphores[SubIndex], (int32)Submits[Index].pWaitDstStageMask[SubIndex]); - } - } - if (Submits[Index].commandBufferCount > 0) - { - DebugLog += FString::Printf(TEXT("\n%s\tCommandBuffers: "), Tabs, Index); - for (uint32 SubIndex = 0; SubIndex < Submits[Index].commandBufferCount; ++SubIndex) - { - DebugLog += FString::Printf(TEXT("%p "), Submits[Index].pCommandBuffers[SubIndex]); - } - } - if (Submits[Index].signalSemaphoreCount > 0) - { - DebugLog += FString::Printf(TEXT("\n%s\tSignalSemaphore: "), Tabs, Index); - for (uint32 SubIndex = 0; SubIndex < Submits[Index].signalSemaphoreCount; ++SubIndex) - { - DebugLog += FString::Printf(TEXT("%p "), Submits[Index].pSignalSemaphores[SubIndex]); - } - } - } - - FlushDebugWrapperLog(); - } - } - - void DumpCreateShaderModule(VkDevice Device, const VkShaderModuleCreateInfo* CreateInfo, VkShaderModule* ShaderModule) - { - DevicePrintfBeginResult(Device, FString::Printf(TEXT("vkCreateShaderModule(CreateInfo=%p, OutShaderModule=%p)[...]"), CreateInfo, ShaderModule)); - } - - void DumpCreatePipelineCache(VkDevice Device, const VkPipelineCacheCreateInfo* CreateInfo, VkPipelineCache* PipelineCache) - { - DevicePrintfBeginResult(Device, FString::Printf(TEXT("vkCreatePipelineCache(CreateInfo=%p, OutPipelineCache=%p)[...]"), CreateInfo, PipelineCache)); - } - - void DumpCreateCommandPool(VkDevice Device, const VkCommandPoolCreateInfo* CreateInfo, VkCommandPool* CommandPool) - { - DevicePrintfBeginResult(Device, FString::Printf(TEXT("vkCreateCommandPool(CreateInfo=%p, OutCommandPool=%p)[...]"), CreateInfo, CommandPool)); - } - - void DumpCreateQueryPool(VkDevice Device, const VkQueryPoolCreateInfo* CreateInfo, VkQueryPool* QueryPool) - { - DevicePrintfBeginResult(Device, FString::Printf(TEXT("vkCreateQueryPool(CreateInfo=%p, OutQueryPool=%p)[...]"), CreateInfo, QueryPool)); - } - - void DumpCreatePipelineLayout(VkDevice Device, const VkPipelineLayoutCreateInfo* CreateInfo, VkPipelineLayout* PipelineLayout) - { - DevicePrintfBeginResult(Device, FString::Printf(TEXT("vkCreatePipelineLayout(CreateInfo=%p, OutPipelineLayout=%p)[...]"), CreateInfo, PipelineLayout)); - } - - void DumpCreateDescriptorPool(VkDevice Device, const VkDescriptorPoolCreateInfo* CreateInfo, VkDescriptorPool* DescriptorPool) - { - DevicePrintfBeginResult(Device, FString::Printf(TEXT("vkCreateDescriptorPool(CreateInfo=%p, OutDescriptorPool=%p)[...]"), CreateInfo, DescriptorPool)); - } - - void DumpCreateSampler(VkDevice Device, const VkSamplerCreateInfo* CreateInfo, VkSampler* Sampler) - { - DevicePrintfBeginResult(Device, FString::Printf(TEXT("vkCreateSampler(CreateInfo=%p, OutSampler=%p)[...]"), CreateInfo, Sampler)); - } - - void DumpCreateDevice(VkPhysicalDevice PhysicalDevice, const VkDeviceCreateInfo* CreateInfo, VkDevice* Device) - { - PrintfBeginResult(FString::Printf(TEXT("vkCreateDevice(PhysicalDevice=%p, CreateInfo=%p, OutDevice=%p)[...]"), PhysicalDevice, CreateInfo, Device)); - } - - void DumpGetPhysicalDeviceFeatures(VkPhysicalDevice PhysicalDevice, VkPhysicalDeviceFeatures* Features) - { - PrintfBeginResult(FString::Printf(TEXT("GetPhysicalDeviceFeatures(PhysicalDevice=%p, Features=%p)[...]"), PhysicalDevice, Features)); - } - - void DumpPhysicalDeviceFeatures(VkPhysicalDeviceFeatures* Features) - { - if (CVarVulkanDumpLayer.GetValueOnAnyThread()) - { - DebugLog += FString::Printf(TEXT("VkPhysicalDeviceFeatures [...]\n")); - } - } - - void DumpBeginCommandBuffer(VkCommandBuffer CommandBuffer, const VkCommandBufferBeginInfo* BeginInfo) - { - FlushDebugWrapperLog(); - - PrintfBeginResult(FString::Printf(TEXT("vkBeginCommandBuffer(CmdBuffer=%p, Info=%p)[...]"), CommandBuffer, BeginInfo)); - } - - void DumpCmdBeginRenderPass(VkCommandBuffer CommandBuffer, const VkRenderPassBeginInfo* RenderPassBegin, VkSubpassContents Contents) - { - if (CVarVulkanDumpLayer.GetValueOnAnyThread()) - { - auto GetSubpassContents = [](VkSubpassContents Contents) -> FString - { - switch (Contents) - { - case VK_SUBPASS_CONTENTS_INLINE: return TEXT("INLINE"); - case VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS: return TEXT("SECONDARY_CMD_BUFS"); - default: return FString::Printf(TEXT("%d"), (int32)Contents); - } - }; - CmdPrintfBegin(CommandBuffer, FString::Printf(TEXT("vkCmdBeginRenderPass(BeginInfo=%p, Contents=%s)"), RenderPassBegin, *GetSubpassContents(Contents))); - DebugLog += FString::Printf(TEXT("%sBeginInfo: RenderPass=%p, Framebuffer=%p, renderArea=(x:%d, y:%d, w:%d, h:%d), clearValues=%d\n"), - Tabs, RenderPassBegin->renderPass, RenderPassBegin->framebuffer, - RenderPassBegin->renderArea.offset.x, RenderPassBegin->renderArea.offset.y, - RenderPassBegin->renderArea.extent.width, RenderPassBegin->renderArea.extent.height, - RenderPassBegin->clearValueCount); - for (uint32 Index = 0; Index < RenderPassBegin->clearValueCount; ++Index) - { - DebugLog += FString::Printf(TEXT("%s\tclearValue[%d]=(%d(%f), %d(%f), %d(%f), %d(%f))\n"), - Tabs, Index, - RenderPassBegin->pClearValues[Index].color.uint32[0], RenderPassBegin->pClearValues[Index].color.float32[0], - RenderPassBegin->pClearValues[Index].color.uint32[1], RenderPassBegin->pClearValues[Index].color.float32[1], - RenderPassBegin->pClearValues[Index].color.uint32[2], RenderPassBegin->pClearValues[Index].color.float32[2], - RenderPassBegin->pClearValues[Index].color.uint32[3], RenderPassBegin->pClearValues[Index].color.float32[3]); - } - } - } - - void DumpCmdBindVertexBuffers(VkCommandBuffer CommandBuffer, uint32 FirstBinding, uint32 BindingCount, const VkBuffer* Buffers, const VkDeviceSize* Offsets) - { - CmdPrintfBegin(CommandBuffer, FString::Printf(TEXT("vkCmdBindVertexBuffers(FirstBinding=%d, NumBindings=%d, Buffers=%p, Offsets=%p)[...]"), FirstBinding, BindingCount, Buffers, Offsets)); - } - - void DumpCmdCopyBufferToImage(VkCommandBuffer CommandBuffer, VkBuffer SrcBuffer, VkImage DstImage, VkImageLayout DstImageLayout, uint32 RegionCount, const VkBufferImageCopy* Regions) - { - CmdPrintfBegin(CommandBuffer, FString::Printf(TEXT("vkCmdCopyBufferToImage(SrcBuffer=%p, DstImage=%p, DstImageLayout=%s, NumRegions=%d, Regions=%p)[...]"), - SrcBuffer, DstImage, *GetImageLayoutString(DstImageLayout), RegionCount, Regions)); - } - - void DumpCmdCopyBuffer(VkCommandBuffer CommandBuffer, VkBuffer SrcBuffer, VkBuffer DstBuffer, uint32 RegionCount, const VkBufferCopy* Regions) - { - CmdPrintfBegin(CommandBuffer, FString::Printf(TEXT("vkCmdCopyBuffer(SrcBuffer=%p, DstBuffer=%p, NumRegions=%d, Regions=%p)[...]"), SrcBuffer, DstBuffer, RegionCount, Regions)); - } - - void DumpGetImageSubresourceLayout(VkDevice Device, VkImage Image, const VkImageSubresource* Subresource, VkSubresourceLayout* Layout) - { - DevicePrintfBeginResult(Device, FString::Printf(TEXT("vkGetImageSubresourceLayout(Image=%p, Subresource=%p, OutLayout=%p)"), Image, Subresource, Layout)); - } - - void DumpImageSubresourceLayout(VkSubresourceLayout* Layout) - { - if (CVarVulkanDumpLayer.GetValueOnAnyThread()) - { - DebugLog += FString::Printf(TEXT("VkSubresourceLayout: [...]\n")); - } - } - - void DumpSwapChainImages(VkResult Result, uint32* SwapchainImageCount, VkImage* SwapchainImages) - { - if (CVarVulkanDumpLayer.GetValueOnAnyThread()) - { - PrintResult(Result); - if (SwapchainImages) - { - for (uint32 Index = 0; Index < *SwapchainImageCount; ++Index) - { - DebugLog += FString::Printf(TEXT("%sImage[%d]=%p\n"), Tabs, Index, SwapchainImages[Index]); - } - } - else - { - DebugLog += FString::Printf(TEXT("%sNumImages=%d\n"), Tabs, *SwapchainImageCount); - } - } - } - - static struct FGlobalDumpLog - { - ~FGlobalDumpLog() - { - FlushDebugWrapperLog(); - } - } GGlobalDumpLogInstance; -} -#endif // VULKAN_ENABLE_DUMP_LAYER -#endif // VULKAN_HAS_DEBUGGING_ENABLED +// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved. + +/*============================================================================= + VulkanDebug.cpp: Vulkan device RHI implementation. +=============================================================================*/ + +#include "VulkanRHIPrivate.h" + +#if VK_HEADER_VERSION < 8 && (VK_API_VERSION < VK_MAKE_VERSION(1, 0, 3)) +#include +#endif + +#define VULKAN_ENABLE_API_DUMP_DETAILED 0 + +#define CREATE_MSG_CALLBACK "vkCreateDebugReportCallbackEXT" +#define DESTROY_MSG_CALLBACK "vkDestroyDebugReportCallbackEXT" + +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* 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) + { + ensure(0); + } + + 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(LayerPrefix), MsgCode); + static TSet SeenCodes; + if (!SeenCodes.Contains(LayerCode)) + { +#if VULKAN_ENABLE_DUMP_LAYER + VulkanRHI::FlushDebugWrapperLog(); +#endif + FString Message = FString::Printf(TEXT("VK ERROR: [%s] Code %d : %s"), ANSI_TO_TCHAR(LayerPrefix), MsgCode, ANSI_TO_TCHAR(Msg)); + FPlatformMisc::LowLevelOutputDebugStringf(TEXT("VulkanRHI: %s\n"), *Message); + UE_LOG(LogVulkanRHI, Error, TEXT("%s"), *Message); + +#if UE_BUILD_DEBUG || UE_BUILD_DEVELOPMENT + //if (!FCStringAnsi::Strcmp(LayerPrefix, "MEM")) + { + //((FVulkanDynamicRHI*)GDynamicRHI)->DumpMemory(); + } +#endif + + // Break debugger on first instance of each message. + // Continuing will ignore the error and suppress this message in future. + bool bIgnoreInFuture = true; + ensureAlways(0); + if (bIgnoreInFuture) + { + SeenCodes.Add(LayerCode); + } + } + return VK_FALSE; + } + else if (MsgFlags & VK_DEBUG_REPORT_WARNING_BIT_EXT) + { +#if VULKAN_ENABLE_DUMP_LAYER + VulkanRHI::FlushDebugWrapperLog(); +#endif + FString Message = FString::Printf(TEXT("VK WARNING: [%s] Code %d : %s\n"), ANSI_TO_TCHAR(LayerPrefix), MsgCode, ANSI_TO_TCHAR(Msg)); + FPlatformMisc::LowLevelOutputDebugStringf(TEXT("VulkanRHI: %s\n"), *Message); + UE_LOG(LogVulkanRHI, Warning, TEXT("%s"), *Message); + return VK_FALSE; + } +#if VULKAN_ENABLE_API_DUMP + else if (MsgFlags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) + { +#if !VULKAN_ENABLE_API_DUMP_DETAILED + if (!FCStringAnsi::Strcmp(LayerPrefix, "MEM") || !FCStringAnsi::Strcmp(LayerPrefix, "DS")) + { + // Skip Mem messages + } + else +#endif + { + FString Message = FString::Printf(TEXT("VK INFO: [%s] Code %d : %s\n"), ANSI_TO_TCHAR(LayerPrefix), MsgCode, ANSI_TO_TCHAR(Msg)); + FPlatformMisc::LowLevelOutputDebugStringf(TEXT("VulkanRHI: %s\n"), *Message); + UE_LOG(LogVulkanRHI, Display, TEXT("%s"), *Message); + } + + return VK_FALSE; + } +#if VULKAN_ENABLE_API_DUMP_DETAILED + else if (MsgFlags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) + { + FString Message = FString::Printf(TEXT("VK DEBUG: [%s] Code %d : %s\n"), ANSI_TO_TCHAR(LayerPrefix), MsgCode, ANSI_TO_TCHAR(Msg)); + FPlatformMisc::LowLevelOutputDebugStringf(TEXT("VulkanRHI: %s\n"), *Message); + UE_LOG(LogVulkanRHI, Display, TEXT("%s"), *Message); + return VK_FALSE; + } +#endif +#endif + + return VK_TRUE; +} + +void FVulkanDynamicRHI::SetupDebugLayerCallback() +{ +#if !VULKAN_DISABLE_DEBUG_CALLBACK + PFN_vkCreateDebugReportCallbackEXT CreateMsgCallback = (PFN_vkCreateDebugReportCallbackEXT)(void*)VulkanRHI::vkGetInstanceProcAddr(Instance, CREATE_MSG_CALLBACK); + if (CreateMsgCallback) + { + VkDebugReportCallbackCreateInfoEXT CreateInfo; + FMemory::Memzero(CreateInfo); + CreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT; + CreateInfo.pfnCallback = DebugReportFunction; + CreateInfo.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT; +#if VULKAN_ENABLE_API_DUMP + CreateInfo.flags |= VK_DEBUG_REPORT_INFORMATION_BIT_EXT; +#if VULKAN_ENABLE_API_DUMP_DETAILED + CreateInfo.flags |= VK_DEBUG_REPORT_DEBUG_BIT_EXT; +#endif +#endif + VkResult Result = CreateMsgCallback(Instance, &CreateInfo, nullptr, &MsgCallback); + switch (Result) + { + case VK_SUCCESS: + break; + case VK_ERROR_OUT_OF_HOST_MEMORY: + UE_LOG(LogVulkanRHI, Warning, TEXT("CreateMsgCallback: out of host memory/CreateMsgCallback Failure; debug reporting skipped")); + break; + default: + UE_LOG(LogVulkanRHI, Warning, TEXT("CreateMsgCallback: unknown failure %d/CreateMsgCallback Failure; debug reporting skipped"), (int32)Result); + break; + } + } + else + { + UE_LOG(LogVulkanRHI, Warning, TEXT("GetProcAddr: Unable to find vkDbgCreateMsgCallback/vkGetInstanceProcAddr; debug reporting skipped!")); + } +#endif +} + +void FVulkanDynamicRHI::RemoveDebugLayerCallback() +{ +#if !VULKAN_DISABLE_DEBUG_CALLBACK + if (MsgCallback != VK_NULL_HANDLE) + { + PFN_vkDestroyDebugReportCallbackEXT DestroyMsgCallback = (PFN_vkDestroyDebugReportCallbackEXT)(void*)VulkanRHI::vkGetInstanceProcAddr(Instance, DESTROY_MSG_CALLBACK); + checkf(DestroyMsgCallback, TEXT("GetProcAddr: Unable to find vkDbgCreateMsgCallback\vkGetInstanceProcAddr Failure")); + DestroyMsgCallback(Instance, MsgCallback, nullptr); + } +#endif +} + + +#if VULKAN_ENABLE_DUMP_LAYER +namespace VulkanRHI +{ + static FString DebugLog; + static int32 DebugLine = 1; + + static const TCHAR* Tabs = TEXT("\t\t\t\t\t\t\t\t\t"); + + void FlushDebugWrapperLog() + { + if (DebugLog.Len() > 0) + { + GLog->Flush(); + UE_LOG(LogVulkanRHI, Display, TEXT("Vulkan Wrapper Log:\n%s"), *DebugLog); + GLog->Flush(); + DebugLog = TEXT(""); + } + } + + static void HandleFlushWrapperLog(const TArray& Args) + { + FlushDebugWrapperLog(); + } + + static FAutoConsoleCommand CVarVulkanFlushLog( + TEXT("r.Vulkan.FlushLog"), + TEXT("\n"), + FConsoleCommandWithArgsDelegate::CreateStatic(&HandleFlushWrapperLog) + ); + + static TAutoConsoleVariable CVarVulkanDumpLayer( + TEXT("r.Vulkan.DumpLayer"), + 0, + TEXT("1 to enable dump layer, 0 to disable (default)") + ); + + static FString GetVkFormatString(VkFormat Format) + { + switch (Format) + { + // + 10 to skip "VK_FORMAT" +#define VKSWITCHCASE(x) case x: return TEXT(#x) + 10; + VKSWITCHCASE(VK_FORMAT_UNDEFINED) + VKSWITCHCASE(VK_FORMAT_R4G4_UNORM_PACK8) + VKSWITCHCASE(VK_FORMAT_R4G4B4A4_UNORM_PACK16) + VKSWITCHCASE(VK_FORMAT_B4G4R4A4_UNORM_PACK16) + VKSWITCHCASE(VK_FORMAT_R5G6B5_UNORM_PACK16) + VKSWITCHCASE(VK_FORMAT_B5G6R5_UNORM_PACK16) + VKSWITCHCASE(VK_FORMAT_R5G5B5A1_UNORM_PACK16) + VKSWITCHCASE(VK_FORMAT_B5G5R5A1_UNORM_PACK16) + VKSWITCHCASE(VK_FORMAT_A1R5G5B5_UNORM_PACK16) + VKSWITCHCASE(VK_FORMAT_R8_UNORM) + VKSWITCHCASE(VK_FORMAT_R8_SNORM) + VKSWITCHCASE(VK_FORMAT_R8_USCALED) + VKSWITCHCASE(VK_FORMAT_R8_SSCALED) + VKSWITCHCASE(VK_FORMAT_R8_UINT) + VKSWITCHCASE(VK_FORMAT_R8_SINT) + VKSWITCHCASE(VK_FORMAT_R8_SRGB) + VKSWITCHCASE(VK_FORMAT_R8G8_UNORM) + VKSWITCHCASE(VK_FORMAT_R8G8_SNORM) + VKSWITCHCASE(VK_FORMAT_R8G8_USCALED) + VKSWITCHCASE(VK_FORMAT_R8G8_SSCALED) + VKSWITCHCASE(VK_FORMAT_R8G8_UINT) + VKSWITCHCASE(VK_FORMAT_R8G8_SINT) + VKSWITCHCASE(VK_FORMAT_R8G8_SRGB) + VKSWITCHCASE(VK_FORMAT_R8G8B8_UNORM) + VKSWITCHCASE(VK_FORMAT_R8G8B8_SNORM) + VKSWITCHCASE(VK_FORMAT_R8G8B8_USCALED) + VKSWITCHCASE(VK_FORMAT_R8G8B8_SSCALED) + VKSWITCHCASE(VK_FORMAT_R8G8B8_UINT) + VKSWITCHCASE(VK_FORMAT_R8G8B8_SINT) + VKSWITCHCASE(VK_FORMAT_R8G8B8_SRGB) + VKSWITCHCASE(VK_FORMAT_B8G8R8_UNORM) + VKSWITCHCASE(VK_FORMAT_B8G8R8_SNORM) + VKSWITCHCASE(VK_FORMAT_B8G8R8_USCALED) + VKSWITCHCASE(VK_FORMAT_B8G8R8_SSCALED) + VKSWITCHCASE(VK_FORMAT_B8G8R8_UINT) + VKSWITCHCASE(VK_FORMAT_B8G8R8_SINT) + VKSWITCHCASE(VK_FORMAT_B8G8R8_SRGB) + VKSWITCHCASE(VK_FORMAT_R8G8B8A8_UNORM) + VKSWITCHCASE(VK_FORMAT_R8G8B8A8_SNORM) + VKSWITCHCASE(VK_FORMAT_R8G8B8A8_USCALED) + VKSWITCHCASE(VK_FORMAT_R8G8B8A8_SSCALED) + VKSWITCHCASE(VK_FORMAT_R8G8B8A8_UINT) + VKSWITCHCASE(VK_FORMAT_R8G8B8A8_SINT) + VKSWITCHCASE(VK_FORMAT_R8G8B8A8_SRGB) + VKSWITCHCASE(VK_FORMAT_B8G8R8A8_UNORM) + VKSWITCHCASE(VK_FORMAT_B8G8R8A8_SNORM) + VKSWITCHCASE(VK_FORMAT_B8G8R8A8_USCALED) + VKSWITCHCASE(VK_FORMAT_B8G8R8A8_SSCALED) + VKSWITCHCASE(VK_FORMAT_B8G8R8A8_UINT) + VKSWITCHCASE(VK_FORMAT_B8G8R8A8_SINT) + VKSWITCHCASE(VK_FORMAT_B8G8R8A8_SRGB) + VKSWITCHCASE(VK_FORMAT_A8B8G8R8_UNORM_PACK32) + VKSWITCHCASE(VK_FORMAT_A8B8G8R8_SNORM_PACK32) + VKSWITCHCASE(VK_FORMAT_A8B8G8R8_USCALED_PACK32) + VKSWITCHCASE(VK_FORMAT_A8B8G8R8_SSCALED_PACK32) + VKSWITCHCASE(VK_FORMAT_A8B8G8R8_UINT_PACK32) + VKSWITCHCASE(VK_FORMAT_A8B8G8R8_SINT_PACK32) + VKSWITCHCASE(VK_FORMAT_A8B8G8R8_SRGB_PACK32) + VKSWITCHCASE(VK_FORMAT_A2R10G10B10_UNORM_PACK32) + VKSWITCHCASE(VK_FORMAT_A2R10G10B10_SNORM_PACK32) + VKSWITCHCASE(VK_FORMAT_A2R10G10B10_USCALED_PACK32) + VKSWITCHCASE(VK_FORMAT_A2R10G10B10_SSCALED_PACK32) + VKSWITCHCASE(VK_FORMAT_A2R10G10B10_UINT_PACK32) + VKSWITCHCASE(VK_FORMAT_A2R10G10B10_SINT_PACK32) + VKSWITCHCASE(VK_FORMAT_A2B10G10R10_UNORM_PACK32) + VKSWITCHCASE(VK_FORMAT_A2B10G10R10_SNORM_PACK32) + VKSWITCHCASE(VK_FORMAT_A2B10G10R10_USCALED_PACK32) + VKSWITCHCASE(VK_FORMAT_A2B10G10R10_SSCALED_PACK32) + VKSWITCHCASE(VK_FORMAT_A2B10G10R10_UINT_PACK32) + VKSWITCHCASE(VK_FORMAT_A2B10G10R10_SINT_PACK32) + VKSWITCHCASE(VK_FORMAT_R16_UNORM) + VKSWITCHCASE(VK_FORMAT_R16_SNORM) + VKSWITCHCASE(VK_FORMAT_R16_USCALED) + VKSWITCHCASE(VK_FORMAT_R16_SSCALED) + VKSWITCHCASE(VK_FORMAT_R16_UINT) + VKSWITCHCASE(VK_FORMAT_R16_SINT) + VKSWITCHCASE(VK_FORMAT_R16_SFLOAT) + VKSWITCHCASE(VK_FORMAT_R16G16_UNORM) + VKSWITCHCASE(VK_FORMAT_R16G16_SNORM) + VKSWITCHCASE(VK_FORMAT_R16G16_USCALED) + VKSWITCHCASE(VK_FORMAT_R16G16_SSCALED) + VKSWITCHCASE(VK_FORMAT_R16G16_UINT) + VKSWITCHCASE(VK_FORMAT_R16G16_SINT) + VKSWITCHCASE(VK_FORMAT_R16G16_SFLOAT) + VKSWITCHCASE(VK_FORMAT_R16G16B16_UNORM) + VKSWITCHCASE(VK_FORMAT_R16G16B16_SNORM) + VKSWITCHCASE(VK_FORMAT_R16G16B16_USCALED) + VKSWITCHCASE(VK_FORMAT_R16G16B16_SSCALED) + VKSWITCHCASE(VK_FORMAT_R16G16B16_UINT) + VKSWITCHCASE(VK_FORMAT_R16G16B16_SINT) + VKSWITCHCASE(VK_FORMAT_R16G16B16_SFLOAT) + VKSWITCHCASE(VK_FORMAT_R16G16B16A16_UNORM) + VKSWITCHCASE(VK_FORMAT_R16G16B16A16_SNORM) + VKSWITCHCASE(VK_FORMAT_R16G16B16A16_USCALED) + VKSWITCHCASE(VK_FORMAT_R16G16B16A16_SSCALED) + VKSWITCHCASE(VK_FORMAT_R16G16B16A16_UINT) + VKSWITCHCASE(VK_FORMAT_R16G16B16A16_SINT) + VKSWITCHCASE(VK_FORMAT_R16G16B16A16_SFLOAT) + VKSWITCHCASE(VK_FORMAT_R32_UINT) + VKSWITCHCASE(VK_FORMAT_R32_SINT) + VKSWITCHCASE(VK_FORMAT_R32_SFLOAT) + VKSWITCHCASE(VK_FORMAT_R32G32_UINT) + VKSWITCHCASE(VK_FORMAT_R32G32_SINT) + VKSWITCHCASE(VK_FORMAT_R32G32_SFLOAT) + VKSWITCHCASE(VK_FORMAT_R32G32B32_UINT) + VKSWITCHCASE(VK_FORMAT_R32G32B32_SINT) + VKSWITCHCASE(VK_FORMAT_R32G32B32_SFLOAT) + VKSWITCHCASE(VK_FORMAT_R32G32B32A32_UINT) + VKSWITCHCASE(VK_FORMAT_R32G32B32A32_SINT) + VKSWITCHCASE(VK_FORMAT_R32G32B32A32_SFLOAT) + VKSWITCHCASE(VK_FORMAT_R64_UINT) + VKSWITCHCASE(VK_FORMAT_R64_SINT) + VKSWITCHCASE(VK_FORMAT_R64_SFLOAT) + VKSWITCHCASE(VK_FORMAT_R64G64_UINT) + VKSWITCHCASE(VK_FORMAT_R64G64_SINT) + VKSWITCHCASE(VK_FORMAT_R64G64_SFLOAT) + VKSWITCHCASE(VK_FORMAT_R64G64B64_UINT) + VKSWITCHCASE(VK_FORMAT_R64G64B64_SINT) + VKSWITCHCASE(VK_FORMAT_R64G64B64_SFLOAT) + VKSWITCHCASE(VK_FORMAT_R64G64B64A64_UINT) + VKSWITCHCASE(VK_FORMAT_R64G64B64A64_SINT) + VKSWITCHCASE(VK_FORMAT_R64G64B64A64_SFLOAT) + VKSWITCHCASE(VK_FORMAT_B10G11R11_UFLOAT_PACK32) + VKSWITCHCASE(VK_FORMAT_E5B9G9R9_UFLOAT_PACK32) + VKSWITCHCASE(VK_FORMAT_D16_UNORM) + VKSWITCHCASE(VK_FORMAT_X8_D24_UNORM_PACK32) + VKSWITCHCASE(VK_FORMAT_D32_SFLOAT) + VKSWITCHCASE(VK_FORMAT_S8_UINT) + VKSWITCHCASE(VK_FORMAT_D16_UNORM_S8_UINT) + VKSWITCHCASE(VK_FORMAT_D24_UNORM_S8_UINT) + VKSWITCHCASE(VK_FORMAT_D32_SFLOAT_S8_UINT) + VKSWITCHCASE(VK_FORMAT_BC1_RGB_UNORM_BLOCK) + VKSWITCHCASE(VK_FORMAT_BC1_RGB_SRGB_BLOCK) + VKSWITCHCASE(VK_FORMAT_BC1_RGBA_UNORM_BLOCK) + VKSWITCHCASE(VK_FORMAT_BC1_RGBA_SRGB_BLOCK) + VKSWITCHCASE(VK_FORMAT_BC2_UNORM_BLOCK) + VKSWITCHCASE(VK_FORMAT_BC2_SRGB_BLOCK) + VKSWITCHCASE(VK_FORMAT_BC3_UNORM_BLOCK) + VKSWITCHCASE(VK_FORMAT_BC3_SRGB_BLOCK) + VKSWITCHCASE(VK_FORMAT_BC4_UNORM_BLOCK) + VKSWITCHCASE(VK_FORMAT_BC4_SNORM_BLOCK) + VKSWITCHCASE(VK_FORMAT_BC5_UNORM_BLOCK) + VKSWITCHCASE(VK_FORMAT_BC5_SNORM_BLOCK) + VKSWITCHCASE(VK_FORMAT_BC6H_UFLOAT_BLOCK) + VKSWITCHCASE(VK_FORMAT_BC6H_SFLOAT_BLOCK) + VKSWITCHCASE(VK_FORMAT_BC7_UNORM_BLOCK) + VKSWITCHCASE(VK_FORMAT_BC7_SRGB_BLOCK) + VKSWITCHCASE(VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK) + VKSWITCHCASE(VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK) + VKSWITCHCASE(VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK) + VKSWITCHCASE(VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK) + VKSWITCHCASE(VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK) + VKSWITCHCASE(VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK) + VKSWITCHCASE(VK_FORMAT_EAC_R11_UNORM_BLOCK) + VKSWITCHCASE(VK_FORMAT_EAC_R11_SNORM_BLOCK) + VKSWITCHCASE(VK_FORMAT_EAC_R11G11_UNORM_BLOCK) + VKSWITCHCASE(VK_FORMAT_EAC_R11G11_SNORM_BLOCK) + VKSWITCHCASE(VK_FORMAT_ASTC_4x4_UNORM_BLOCK) + VKSWITCHCASE(VK_FORMAT_ASTC_4x4_SRGB_BLOCK) + VKSWITCHCASE(VK_FORMAT_ASTC_5x4_UNORM_BLOCK) + VKSWITCHCASE(VK_FORMAT_ASTC_5x4_SRGB_BLOCK) + VKSWITCHCASE(VK_FORMAT_ASTC_5x5_UNORM_BLOCK) + VKSWITCHCASE(VK_FORMAT_ASTC_5x5_SRGB_BLOCK) + VKSWITCHCASE(VK_FORMAT_ASTC_6x5_UNORM_BLOCK) + VKSWITCHCASE(VK_FORMAT_ASTC_6x5_SRGB_BLOCK) + VKSWITCHCASE(VK_FORMAT_ASTC_6x6_UNORM_BLOCK) + VKSWITCHCASE(VK_FORMAT_ASTC_6x6_SRGB_BLOCK) + VKSWITCHCASE(VK_FORMAT_ASTC_8x5_UNORM_BLOCK) + VKSWITCHCASE(VK_FORMAT_ASTC_8x5_SRGB_BLOCK) + VKSWITCHCASE(VK_FORMAT_ASTC_8x6_UNORM_BLOCK) + VKSWITCHCASE(VK_FORMAT_ASTC_8x6_SRGB_BLOCK) + VKSWITCHCASE(VK_FORMAT_ASTC_8x8_UNORM_BLOCK) + VKSWITCHCASE(VK_FORMAT_ASTC_8x8_SRGB_BLOCK) + VKSWITCHCASE(VK_FORMAT_ASTC_10x5_UNORM_BLOCK) + VKSWITCHCASE(VK_FORMAT_ASTC_10x5_SRGB_BLOCK) + VKSWITCHCASE(VK_FORMAT_ASTC_10x6_UNORM_BLOCK) + VKSWITCHCASE(VK_FORMAT_ASTC_10x6_SRGB_BLOCK) + VKSWITCHCASE(VK_FORMAT_ASTC_10x8_UNORM_BLOCK) + VKSWITCHCASE(VK_FORMAT_ASTC_10x8_SRGB_BLOCK) + VKSWITCHCASE(VK_FORMAT_ASTC_10x10_UNORM_BLOCK) + VKSWITCHCASE(VK_FORMAT_ASTC_10x10_SRGB_BLOCK) + VKSWITCHCASE(VK_FORMAT_ASTC_12x10_UNORM_BLOCK) + VKSWITCHCASE(VK_FORMAT_ASTC_12x10_SRGB_BLOCK) + VKSWITCHCASE(VK_FORMAT_ASTC_12x12_UNORM_BLOCK) + VKSWITCHCASE(VK_FORMAT_ASTC_12x12_SRGB_BLOCK) +#undef VKSWITCHCASE + default: + break; + } + return FString::Printf(TEXT("Unknown VkFormat %d"), (int32)Format); + } + + static FString GetVkResultErrorString(VkResult Result) + { + switch (Result) + { + // + 3 to skip "VK_" +#define VKSWITCHCASE(x) case x: return TEXT(#x) + 3; + VKSWITCHCASE(VK_SUCCESS) + VKSWITCHCASE(VK_NOT_READY) + VKSWITCHCASE(VK_TIMEOUT) + VKSWITCHCASE(VK_EVENT_SET) + VKSWITCHCASE(VK_EVENT_RESET) + VKSWITCHCASE(VK_INCOMPLETE) + VKSWITCHCASE(VK_ERROR_OUT_OF_HOST_MEMORY) + VKSWITCHCASE(VK_ERROR_OUT_OF_DEVICE_MEMORY) + VKSWITCHCASE(VK_ERROR_INITIALIZATION_FAILED) + VKSWITCHCASE(VK_ERROR_DEVICE_LOST) + VKSWITCHCASE(VK_ERROR_MEMORY_MAP_FAILED) + VKSWITCHCASE(VK_ERROR_LAYER_NOT_PRESENT) + VKSWITCHCASE(VK_ERROR_EXTENSION_NOT_PRESENT) + VKSWITCHCASE(VK_ERROR_FEATURE_NOT_PRESENT) + VKSWITCHCASE(VK_ERROR_INCOMPATIBLE_DRIVER) + VKSWITCHCASE(VK_ERROR_TOO_MANY_OBJECTS) + VKSWITCHCASE(VK_ERROR_FORMAT_NOT_SUPPORTED) + VKSWITCHCASE(VK_ERROR_SURFACE_LOST_KHR) + VKSWITCHCASE(VK_ERROR_NATIVE_WINDOW_IN_USE_KHR) + VKSWITCHCASE(VK_SUBOPTIMAL_KHR) + VKSWITCHCASE(VK_ERROR_OUT_OF_DATE_KHR) + VKSWITCHCASE(VK_ERROR_INCOMPATIBLE_DISPLAY_KHR) + VKSWITCHCASE(VK_ERROR_VALIDATION_FAILED_EXT) + VKSWITCHCASE(VK_ERROR_INVALID_SHADER_NV) +#undef VKSWITCHCASE + default: + break; + } + + return FString::Printf(TEXT("Unknown VkResult %d"), (int32)Result); + } + + FString GetImageTilingString(VkImageTiling Tiling) + { + switch (Tiling) + { + // + 16 to skip "VK_IMAGE_TILING_" +#define VKSWITCHCASE(x) case x: return TEXT(#x) + 16; + VKSWITCHCASE(VK_IMAGE_TILING_OPTIMAL) + VKSWITCHCASE(VK_IMAGE_TILING_LINEAR) +#undef VKSWITCHCASE + default: + break; + } + + return FString::Printf(TEXT("Unknown VkImageTiling %d"), (int32)Tiling); + } + + static FString GetImageLayoutString(VkImageLayout Layout) + { + switch (Layout) + { + // + 16 to skip "VK_IMAGE_LAYOUT" +#define VKSWITCHCASE(x) case x: return TEXT(#x) + 16; + VKSWITCHCASE(VK_IMAGE_LAYOUT_UNDEFINED) + VKSWITCHCASE(VK_IMAGE_LAYOUT_GENERAL) + VKSWITCHCASE(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) + VKSWITCHCASE(VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) + VKSWITCHCASE(VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL) + VKSWITCHCASE(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) + VKSWITCHCASE(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) + VKSWITCHCASE(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) + VKSWITCHCASE(VK_IMAGE_LAYOUT_PREINITIALIZED) + VKSWITCHCASE(VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) +#undef VKSWITCHCASE + default: + break; + } + + return FString::Printf(TEXT("Unknown VkImageLayout %d"), (int32)Layout); + } + + static FString GetImageViewTypeString(VkImageViewType Type) + { + switch (Type) + { + // + 19 to skip "VK_IMAGE_VIEW_TYPE_" +#define VKSWITCHCASE(x) case x: return TEXT(#x) + 16; + VKSWITCHCASE(VK_IMAGE_VIEW_TYPE_1D) + VKSWITCHCASE(VK_IMAGE_VIEW_TYPE_2D) + VKSWITCHCASE(VK_IMAGE_VIEW_TYPE_3D) + VKSWITCHCASE(VK_IMAGE_VIEW_TYPE_CUBE) + VKSWITCHCASE(VK_IMAGE_VIEW_TYPE_1D_ARRAY) + VKSWITCHCASE(VK_IMAGE_VIEW_TYPE_2D_ARRAY) + VKSWITCHCASE(VK_IMAGE_VIEW_TYPE_CUBE_ARRAY) +#undef VKSWITCHCASE + default: + break; + } + + return FString::Printf(TEXT("Unknown VkImageViewType %d"), (int32)Type); + } + + static FString GetComponentMappingString(const VkComponentMapping& Mapping) + { + auto GetSwizzle = [](VkComponentSwizzle Swizzle) -> const TCHAR* + { + switch (Swizzle) + { + case VK_COMPONENT_SWIZZLE_IDENTITY: return TEXT("ID"); + case VK_COMPONENT_SWIZZLE_ZERO: return TEXT("0"); + case VK_COMPONENT_SWIZZLE_ONE: return TEXT("1"); + case VK_COMPONENT_SWIZZLE_R: return TEXT("R"); + case VK_COMPONENT_SWIZZLE_G: return TEXT("G"); + case VK_COMPONENT_SWIZZLE_B: return TEXT("B"); + case VK_COMPONENT_SWIZZLE_A: return TEXT("A"); + default: + check(0); + return TEXT("-"); + } + }; + return FString::Printf(TEXT("(r=%s, g=%s, b=%s, a=%s)"), GetSwizzle(Mapping.r), GetSwizzle(Mapping.g), GetSwizzle(Mapping.b), GetSwizzle(Mapping.a)); + } + + +#define AppendBitFieldName(BitField, Name) \ + if ((Flags & BitField) == BitField)\ + {\ + Flags &= ~BitField;\ + if (String.Len() > 0)\ + {\ + String += TEXT("|");\ + }\ + String += Name;\ + } + + static FString GetAspectMaskString(VkImageAspectFlags Flags) + { + if (Flags == 0) + { + return TEXT("0"); + } + FString String; + AppendBitFieldName(VK_IMAGE_ASPECT_COLOR_BIT, TEXT("COLOR")); + AppendBitFieldName(VK_IMAGE_ASPECT_DEPTH_BIT, TEXT("DEPTH")); + AppendBitFieldName(VK_IMAGE_ASPECT_STENCIL_BIT, TEXT("STENCIL")); + AppendBitFieldName(VK_IMAGE_ASPECT_METADATA_BIT, TEXT("METADATA")); + if (Flags != 0) + { + FString Unknown = FString::Printf(TEXT("%d"), Flags); + AppendBitFieldName(Flags, Unknown); + } + return String; + } + + static FString GetAccessFlagString(VkAccessFlags Flags) + { + if (Flags == 0) + { + return TEXT("0"); + } + FString String; + AppendBitFieldName(VK_ACCESS_INDIRECT_COMMAND_READ_BIT, TEXT("INDIRECT_COMMAND")); + AppendBitFieldName(VK_ACCESS_INDEX_READ_BIT, TEXT("INDEX_READ")); + AppendBitFieldName(VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT, TEXT("VERTEX_ATTR_READ")); + AppendBitFieldName(VK_ACCESS_UNIFORM_READ_BIT, TEXT("UNIF_READ")); + AppendBitFieldName(VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, TEXT("INPUT_ATT_READ")); + AppendBitFieldName(VK_ACCESS_SHADER_READ_BIT, TEXT("SHADER_READ")); + AppendBitFieldName(VK_ACCESS_SHADER_WRITE_BIT, TEXT("SHADER_WRITE")); + AppendBitFieldName(VK_ACCESS_COLOR_ATTACHMENT_READ_BIT, TEXT("COLOR_ATT_READ")); + AppendBitFieldName(VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, TEXT("COLOR_ATT_WRITE")); + AppendBitFieldName(VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT, TEXT("DS_ATT_READ")); + AppendBitFieldName(VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, TEXT("DS_ATT_WIRTE")); + AppendBitFieldName(VK_ACCESS_TRANSFER_READ_BIT, TEXT("TRANSFER_READ")); + AppendBitFieldName(VK_ACCESS_TRANSFER_WRITE_BIT, TEXT("TRANSFER_WRITE")); + AppendBitFieldName(VK_ACCESS_HOST_READ_BIT, TEXT("HOST_READ")); + AppendBitFieldName(VK_ACCESS_HOST_WRITE_BIT, TEXT("HOST_WRITE")); + AppendBitFieldName(VK_ACCESS_MEMORY_READ_BIT, TEXT("MEM_READ")); + AppendBitFieldName(VK_ACCESS_MEMORY_WRITE_BIT, TEXT("MEM_WRITE")); + if (Flags != 0) + { + FString Unknown = FString::Printf(TEXT("%d"), Flags); + AppendBitFieldName(Flags, Unknown); + } + return String; + } + + FString GetSampleCountString(VkSampleCountFlags Flags) + { + if (Flags == 0) + { + return TEXT("0"); + } + FString String; + AppendBitFieldName(VK_SAMPLE_COUNT_1_BIT, TEXT("1")); + AppendBitFieldName(VK_SAMPLE_COUNT_2_BIT, TEXT("2")); + AppendBitFieldName(VK_SAMPLE_COUNT_4_BIT, TEXT("4")); + AppendBitFieldName(VK_SAMPLE_COUNT_8_BIT, TEXT("8")); + AppendBitFieldName(VK_SAMPLE_COUNT_16_BIT, TEXT("16")); + AppendBitFieldName(VK_SAMPLE_COUNT_32_BIT, TEXT("32")); + AppendBitFieldName(VK_SAMPLE_COUNT_64_BIT, TEXT("64")); + if (Flags != 0) + { + FString Unknown = FString::Printf(TEXT("%d"), Flags); + AppendBitFieldName(Flags, Unknown); + } + return String; + } + + FString GetImageUsageString(VkImageUsageFlags Flags) + { + if (Flags == 0) + { + return TEXT("0"); + } + FString String; + AppendBitFieldName(VK_IMAGE_USAGE_TRANSFER_SRC_BIT, TEXT("XFER_SRC")); + AppendBitFieldName(VK_IMAGE_USAGE_TRANSFER_DST_BIT, TEXT("XFER_DST")); + AppendBitFieldName(VK_IMAGE_USAGE_SAMPLED_BIT, TEXT("SAMPLED")); + AppendBitFieldName(VK_IMAGE_USAGE_STORAGE_BIT, TEXT("STORAGE")); + AppendBitFieldName(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, TEXT("COLOR_ATT")); + AppendBitFieldName(VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, TEXT("DS_ATT")); + AppendBitFieldName(VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT, TEXT("TRANS_ATT")); + AppendBitFieldName(VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT, TEXT("IN_ATT")); + if (Flags != 0) + { + FString Unknown = FString::Printf(TEXT("%d"), Flags); + AppendBitFieldName(Flags, Unknown); + } + return String; + } +#undef AppendBitFieldName + + FString GetExtentString(const VkExtent3D& Extent) + { + return FString::Printf(TEXT("w:%d h:%d d:%d"), Extent.width, Extent.height, Extent.depth); + } + + FString GetExtentString(const VkExtent2D& Extent) + { + return FString::Printf(TEXT("w:%d h:%d"), Extent.width, Extent.height); + } + + static FString GetSubResourceRangeString(const VkImageSubresourceRange& Range) + { + return FString::Printf(TEXT("aspectMask=%s, baseMipLevel=%d, levelCount=%d, baseArrayLayer=%d, layerCount=%d"), *GetAspectMaskString(Range.aspectMask), Range.baseMipLevel, Range.levelCount, Range.baseArrayLayer, Range.layerCount); + } + + static FString GetStageMaskString(VkPipelineStageFlags Flags) + { + return FString::Printf(TEXT("VkPipelineStageFlags=0x%x"), (uint32)Flags); + } + + void PrintfBeginResult(const FString& String) + { + if (CVarVulkanDumpLayer.GetValueOnAnyThread()) + { + DebugLog += FString::Printf(TEXT("[GLOBAL METHOD] %8d: %s"), DebugLine++, *String); + } + } + + void PrintfBegin(const FString& String) + { + if (CVarVulkanDumpLayer.GetValueOnAnyThread()) + { + DebugLog += FString::Printf(TEXT("[GLOBAL METHOD] %8d: %s\n"), DebugLine++, *String); + } + } + + void DevicePrintfBeginResult(VkDevice Device, const FString& String) + { + if (CVarVulkanDumpLayer.GetValueOnAnyThread()) + { + DebugLog += FString::Printf(TEXT("[D:%p]%8d: %s"), Device, DebugLine++, *String); + } + } + + void DevicePrintfBegin(VkDevice Device, const FString& String) + { + if (CVarVulkanDumpLayer.GetValueOnAnyThread()) + { + DebugLog += FString::Printf(TEXT("[D:%p]%8d: %s\n"), Device, DebugLine++, *String); + } + } + + void CmdPrintfBegin(VkCommandBuffer CmdBuffer, const FString& String) + { + if (CVarVulkanDumpLayer.GetValueOnAnyThread()) + { + DebugLog += FString::Printf(TEXT("[C:%p]%8d: %s\n"), CmdBuffer, DebugLine++, *String); + } + } + + void CmdPrintfBeginResult(VkCommandBuffer CmdBuffer, const FString& String) + { + if (CVarVulkanDumpLayer.GetValueOnAnyThread()) + { + DebugLog += FString::Printf(TEXT("[C:%p]%8d: %s"), CmdBuffer, DebugLine++, *String); + } + } + + void PrintResult(VkResult Result) + { + if (CVarVulkanDumpLayer.GetValueOnAnyThread()) + { + DebugLog += FString::Printf(TEXT(" -> %s\n"), *GetVkResultErrorString(Result)); + if (Result < VK_SUCCESS) + { + FlushDebugWrapperLog(); + } + } + } + + void PrintResultAndPointer(VkResult Result, void* Handle) + { + if (CVarVulkanDumpLayer.GetValueOnAnyThread()) + { + DebugLog += FString::Printf(TEXT(" -> %s => %p\n"), *GetVkResultErrorString(Result), Handle); + if (Result < VK_SUCCESS) + { + FlushDebugWrapperLog(); + } + } + } + + void PrintResultAndNamedHandle(VkResult Result, const TCHAR* HandleName, void* Handle) + { + if (CVarVulkanDumpLayer.GetValueOnAnyThread()) + { + DebugLog += FString::Printf(TEXT(" -> %s => %s=%p\n"), *GetVkResultErrorString(Result), HandleName, Handle); + if (Result < VK_SUCCESS) + { + FlushDebugWrapperLog(); + } + } + } + + void DumpPhysicalDeviceProperties(VkPhysicalDeviceMemoryProperties* Properties) + { + if (CVarVulkanDumpLayer.GetValueOnAnyThread()) + { + DebugLog += FString::Printf(TEXT(" -> VkPhysicalDeviceMemoryProperties[...]\n")); + } + } + + void DumpAllocateMemory(VkDevice Device, const VkMemoryAllocateInfo* AllocateInfo, VkDeviceMemory* Memory) + { + if (CVarVulkanDumpLayer.GetValueOnAnyThread()) + { + DevicePrintfBeginResult(Device, FString::Printf(TEXT("vkAllocateMemory(OutMem=%p): Size=%d, MemTypeIndex=%d"), AllocateInfo, Memory, (uint32)AllocateInfo->allocationSize, AllocateInfo->memoryTypeIndex)); + } + } + + void DumpMemoryRequirements(VkMemoryRequirements* MemoryRequirements) + { + if (CVarVulkanDumpLayer.GetValueOnAnyThread()) + { + DebugLog += FString::Printf(TEXT(" -> Size=%d Align=%d MemTypeBits=0x%x\n"), (uint32)MemoryRequirements->size, (uint32)MemoryRequirements->alignment, MemoryRequirements->memoryTypeBits); + } + } + + void DumpCreateBuffer(VkDevice Device, const VkBufferCreateInfo* CreateInfo, VkBuffer* Buffer) + { + FlushDebugWrapperLog(); + DevicePrintfBeginResult(Device, FString::Printf(TEXT("vkCreateBuffer(Info=%p, OutBuffer=%p)[...]"), CreateInfo, Buffer)); + } + + void DumpCreateBufferView(VkDevice Device, const VkBufferViewCreateInfo* CreateInfo, VkBufferView* BufferView) + { + DevicePrintfBeginResult(Device, FString::Printf(TEXT("VkBufferViewCreateInfo(Info=%p, OutBufferView=%p)[...]"), CreateInfo, BufferView)); + } + + void DumpCreateImage(VkDevice Device, const VkImageCreateInfo* CreateInfo, VkImage* Image) + { + if (CVarVulkanDumpLayer.GetValueOnAnyThread()) + { + FlushDebugWrapperLog(); + DevicePrintfBegin(Device, FString::Printf(TEXT("vkCreateImage(Info=%p, OutImage=%p)"), CreateInfo, Image)); + DebugLog += FString::Printf(TEXT("%sVkImageCreateInfo: Flags=%d, ImageType=%d, Format=%s, MipLevels=%d, ArrayLayers=%d, Samples=%s\n"), Tabs, CreateInfo->flags, (uint32)CreateInfo->imageType, + *GetVkFormatString(CreateInfo->format), CreateInfo->mipLevels, CreateInfo->arrayLayers, *GetSampleCountString(CreateInfo->samples)); + DebugLog += FString::Printf(TEXT("%s\tExtent=(%s) Tiling=%s, Usage=%s, Initial=%s\n"), Tabs, *GetExtentString(CreateInfo->extent), + *GetImageTilingString(CreateInfo->tiling), *GetImageUsageString(CreateInfo->usage), *GetImageLayoutString(CreateInfo->initialLayout)); + } + } + + void DumpCreateImageView(VkDevice Device, const VkImageViewCreateInfo* CreateInfo, VkImageView* ImageView) + { + if (CVarVulkanDumpLayer.GetValueOnAnyThread()) + { + DevicePrintfBegin(Device, FString::Printf(TEXT("vkCreateImageView(Info=%p, OutImageView=%p)"), CreateInfo, ImageView)); + DebugLog += FString::Printf(TEXT("%sVkImageViewCreateInfo: Flags=%d, Image=%p, ViewType=%s, Format=%s, Components=%s\n"), Tabs, CreateInfo->flags, CreateInfo->image, + *GetImageViewTypeString(CreateInfo->viewType), *GetVkFormatString(CreateInfo->format), *GetComponentMappingString(CreateInfo->components)); + DebugLog += FString::Printf(TEXT("%s\tSubresourceRange=(%s)"), Tabs, *GetSubResourceRangeString(CreateInfo->subresourceRange)); + } + } + + void DumpFenceCreate(VkDevice Device, const VkFenceCreateInfo* CreateInfo, VkFence* Fence) + { + DevicePrintfBeginResult(Device, FString::Printf(TEXT("vkCreateFence(CreateInfo=%p, OutFence=%p)[...]"), CreateInfo, Fence)); + } + + void DumpFenceList(uint32 FenceCount, const VkFence* Fences) + { + if (CVarVulkanDumpLayer.GetValueOnAnyThread()) + { + for (uint32 Index = 0; Index < FenceCount; ++Index) + { + DebugLog += Tabs; + DebugLog += '\t'; + DebugLog += FString::Printf(TEXT("Fence[%d]=%p"), Index, Fences[Index]); + if (Index < FenceCount - 1) + { + DebugLog += TEXT("\n"); + } + } + } + } + + void DumpSemaphoreCreate(VkDevice Device, const VkSemaphoreCreateInfo* CreateInfo, VkSemaphore* Semaphore) + { + DevicePrintfBeginResult(Device, FString::Printf(TEXT("vkCreateSemaphore(CreateInfo=%p, OutSemaphore=%p)[...]"), CreateInfo, Semaphore)); + } + + void DumpMappedMemoryRanges(uint32 memoryRangeCount, const VkMappedMemoryRange* MemoryRanges) + { + ensure(0); + } + + void DumpResolveImage(VkCommandBuffer CommandBuffer, VkImage SrcImage, VkImageLayout SrcImageLayout, VkImage DstImage, VkImageLayout DstImageLayout, uint32 RegionCount, const VkImageResolve* Regions) + { + if (CVarVulkanDumpLayer.GetValueOnAnyThread()) + { + CmdPrintfBegin(CommandBuffer, FString::Printf(TEXT("vkCmdResolveImage(SrcImage=%p, SrcImageLayout=%s, DestImage=%p, DestImageLayout=%s, NumRegions=%d, Regions=%p)[...]"), + CommandBuffer, SrcImage, *GetImageLayoutString(SrcImageLayout), DstImage, *GetImageLayoutString(DstImageLayout), RegionCount, Regions)); + for (uint32 Index = 0; Index < RegionCount; ++Index) + { + DebugLog += Tabs; + DebugLog += FString::Printf(TEXT("Region %d: "), Index); + /* + typedef struct VkImageResolve { + VkImageSubresourceLayers srcSubresource; + VkOffset3D srcOffset; + VkImageSubresourceLayers dstSubresource; + VkOffset3D dstOffset; + VkExtent3D extent; + + */ + } + } + } + + void DumpFreeDescriptorSets(VkDevice Device, VkDescriptorPool DescriptorPool, uint32 DescriptorSetCount, const VkDescriptorSet* DescriptorSets) + { + if (CVarVulkanDumpLayer.GetValueOnAnyThread()) + { + DevicePrintfBegin(Device, FString::Printf(TEXT("vkFreeDescriptorSets(Pool=%p, NumSets=%d, Sets=%p)"), DescriptorPool, DescriptorSetCount, DescriptorSets)); + for (uint32 Index = 0; Index < DescriptorSetCount; ++Index) + { + DebugLog += Tabs; + DebugLog += FString::Printf(TEXT("Set %d: %p\n"), Index, DescriptorSets[Index]); + } + } + } + + void DumpCreateInstance(const VkInstanceCreateInfo* CreateInfo, VkInstance* Instance) + { + PrintfBegin(FString::Printf(TEXT("vkCreateInstance(Info=%p, OutInstance=%p)[...]"), CreateInfo, Instance)); + } + + void DumpEnumeratePhysicalDevicesEpilog(uint32* PhysicalDeviceCount, VkPhysicalDevice* PhysicalDevices) + { + if (CVarVulkanDumpLayer.GetValueOnAnyThread()) + { + if (PhysicalDeviceCount) + { + DebugLog += Tabs; + DebugLog += FString::Printf(TEXT("OutCount=%d\n"), *PhysicalDeviceCount); + if (PhysicalDevices) + { + for (uint32 Index = 0; Index < *PhysicalDeviceCount; ++Index) + { + DebugLog += Tabs; + DebugLog += FString::Printf(TEXT("\tOutDevice[%d]=%p\n"), Index, PhysicalDevices[Index]); + } + } + } + } + } + + void DumpCmdPipelineBarrier(VkCommandBuffer CommandBuffer, VkPipelineStageFlags SrcStageMask, VkPipelineStageFlags DstStageMask, VkDependencyFlags DependencyFlags, uint32 MemoryBarrierCount, const VkMemoryBarrier* MemoryBarriers, uint32 BufferMemoryBarrierCount, const VkBufferMemoryBarrier* BufferMemoryBarriers, uint32 ImageMemoryBarrierCount, const VkImageMemoryBarrier* ImageMemoryBarriers) + { + CmdPrintfBegin(CommandBuffer, FString::Printf(TEXT("vkCmdPipelineBarrier(SrcMask=%s, DestMask=%s, Flags=%d, NumMemB=%d, MemB=%p,"), *GetStageMaskString(SrcStageMask), *GetStageMaskString(DstStageMask), (uint32)DependencyFlags, MemoryBarrierCount, MemoryBarriers)); + if (CVarVulkanDumpLayer.GetValueOnAnyThread()) + { + DebugLog += FString::Printf(TEXT("%s\tNumBufferB=%d, BufferB=%p, NumImageB=%d, ImageB=%p)[...]\n"), Tabs, BufferMemoryBarrierCount, BufferMemoryBarriers, ImageMemoryBarrierCount, ImageMemoryBarriers); + if (ImageMemoryBarrierCount) + { + for (uint32 Index = 0; Index < ImageMemoryBarrierCount; ++Index) + { + DebugLog += FString::Printf(TEXT("%s\tImageBarrier[%d]: srcAccess=%s, oldLayout=%s, srcQueueFamilyIndex=%d\n"), Tabs, Index, *GetAccessFlagString(ImageMemoryBarriers[Index].srcAccessMask), *GetImageLayoutString(ImageMemoryBarriers[Index].oldLayout), ImageMemoryBarriers[Index].srcQueueFamilyIndex); + DebugLog += FString::Printf(TEXT("%s\t\tdstAccess=%s, newLayout=%s, dstQueueFamilyIndex=%d\n"), Tabs, *GetAccessFlagString(ImageMemoryBarriers[Index].dstAccessMask), *GetImageLayoutString(ImageMemoryBarriers[Index].newLayout), ImageMemoryBarriers[Index].dstQueueFamilyIndex); + DebugLog += FString::Printf(TEXT("%s\t\tImage=%p, subresourceRange=(%s)\n"), Tabs, ImageMemoryBarriers[Index].image, *GetSubResourceRangeString(ImageMemoryBarriers[Index].subresourceRange)); + } + } + } + } + + void DumpBindDescriptorSets(VkCommandBuffer CommandBuffer, VkPipelineBindPoint PipelineBindPoint, VkPipelineLayout Layout, uint32 FirstSet, uint32 DescriptorSetCount, const VkDescriptorSet* DescriptorSets, uint32 DynamicOffsetCount, const uint32* DynamicOffsets) + { + CmdPrintfBegin(CommandBuffer, FString::Printf(TEXT("vkCmdBindDescriptorSets(PipelineBindPoint=%d, Layout=%p, FirstSet=%d, NumDS=%d, DS=%p, NumDynamicOffset=%d, DynamicOffsets=%p)[...]"), (int32)PipelineBindPoint, Layout, FirstSet, DescriptorSetCount, DescriptorSets, DynamicOffsetCount, DynamicOffsets)); + if (CVarVulkanDumpLayer.GetValueOnAnyThread()) + { + for (uint32 Index = 0; Index < DescriptorSetCount; ++Index) + { + DebugLog += FString::Printf(TEXT("%s\tDS[%d]=%p\n"), Tabs, Index, DescriptorSets[Index]); + } + for (uint32 Index = 0; Index < DynamicOffsetCount; ++Index) + { + DebugLog += FString::Printf(TEXT("%s\tDynamicOffset[%d]=%p\n"), Tabs, Index, DynamicOffsets[Index]); + } + } + } + + void DumpCreateDescriptorSetLayout(VkDevice Device, const VkDescriptorSetLayoutCreateInfo* CreateInfo, VkDescriptorSetLayout* SetLayout) + { + DevicePrintfBegin(Device, FString::Printf(TEXT("vkCreateDescriptorSetLayout(Info=%p, OutLayout=%p)[...]"), CreateInfo, SetLayout)); + } + + void DumpAllocateDescriptorSets(VkDevice Device, const VkDescriptorSetAllocateInfo* AllocateInfo, VkDescriptorSet* DescriptorSets) + { + DevicePrintfBegin(Device, FString::Printf(TEXT("vkAllocateDescriptorSets(Info=%p, OutSets=%p)[...]"), AllocateInfo, DescriptorSets)); + } + + void DumpUpdateDescriptorSets(VkDevice Device, uint32 DescriptorWriteCount, const VkWriteDescriptorSet* DescriptorWrites, uint32 DescriptorCopyCount, const VkCopyDescriptorSet* DescriptorCopies) + { + DevicePrintfBegin(Device, FString::Printf(TEXT("vkUpdateDescriptorSets(NumWrites=%d, Writes=%p, NumCopies=%d, Copies=%p)[...]"), DescriptorWriteCount, DescriptorWrites, DescriptorCopyCount, DescriptorCopies)); + } + + void DumpCreateFramebuffer(VkDevice Device, const VkFramebufferCreateInfo* CreateInfo, VkFramebuffer* Framebuffer) + { + if (CVarVulkanDumpLayer.GetValueOnAnyThread()) + { + DevicePrintfBegin(Device, FString::Printf(TEXT("vkCreateFramebuffer(Info=%p, OutFramebuffer=%p)"), CreateInfo, Framebuffer)); + DebugLog += FString::Printf(TEXT("%sVkFramebufferCreateInfo: Flags=%d, RenderPass=%p, NumAttachments=%d\n"), Tabs, CreateInfo->flags, CreateInfo->renderPass, CreateInfo->attachmentCount); + for (uint32 Index = 0; Index < CreateInfo->attachmentCount; ++Index) + { + DebugLog += FString::Printf(TEXT("%s\tAttachment[%d]: ImageView=%p\n"), Tabs, Index, CreateInfo->pAttachments[Index]); + } + DebugLog += FString::Printf(TEXT("%s\twidth=%d, height=%d, layers=%d"), Tabs, CreateInfo->width, CreateInfo->height, CreateInfo->layers); + } + } + + void DumpCreateRenderPass(VkDevice Device, const VkRenderPassCreateInfo* CreateInfo, VkRenderPass* RenderPass) + { + if (CVarVulkanDumpLayer.GetValueOnAnyThread()) + { + DevicePrintfBegin(Device, FString::Printf(TEXT("vkCreateRenderPass(Info=%p, OutRenderPass=%p)[...]"), CreateInfo, RenderPass)); + DebugLog += FString::Printf(TEXT("%s\tVkRenderPassCreateInfo: NumAttachments=%d, Attachments=%p, NumSubPasses=%d, SubPasses=%p\n"), Tabs, CreateInfo->attachmentCount, CreateInfo->pAttachments, CreateInfo->subpassCount, CreateInfo->pSubpasses); + for (uint32 Index = 0; Index < CreateInfo->attachmentCount; ++Index) + { + auto GetLoadOpString = [](VkAttachmentLoadOp Op) -> FString + { + switch (Op) + { + case VK_ATTACHMENT_LOAD_OP_LOAD: return TEXT("LOAD"); + case VK_ATTACHMENT_LOAD_OP_CLEAR: return TEXT("CLEAR"); + case VK_ATTACHMENT_LOAD_OP_DONT_CARE: return TEXT("DONT_CARE"); + default: return FString::Printf(TEXT("Invalid(%d)"), (uint32)Op); + } + }; + auto GetStoreOpString = [](VkAttachmentStoreOp Op) -> FString + { + switch(Op) + { + case VK_ATTACHMENT_STORE_OP_STORE: return TEXT("STORE"); + case VK_ATTACHMENT_STORE_OP_DONT_CARE: return TEXT("DONT_CARE"); + default: return FString::Printf(TEXT("Invalid(%d)"), (uint32)Op); + } + }; + /* + typedef struct VkAttachmentDescription { + VkAttachmentDescriptionFlags flags; + VkFormat format; + VkSampleCountFlagBits samples; + VkAttachmentLoadOp loadOp; + VkAttachmentStoreOp storeOp; + VkAttachmentLoadOp stencilLoadOp; + VkAttachmentStoreOp stencilStoreOp; + VkImageLayout initialLayout; + VkImageLayout finalLayout; + } VkAttachmentDescription; +*/ + const VkAttachmentDescription& Desc = CreateInfo->pAttachments[Index]; + DebugLog += FString::Printf(TEXT("%s\t\tAttachment[%d]: Flags=%s, Format=%s, Samples=%s, Load=%s, Store=%s\n"), Tabs, Index, + (Desc.flags == VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT ? TEXT("MAY_ALIAS") : TEXT("0")), + *GetVkFormatString(Desc.format), *GetSampleCountString(Desc.samples), *GetLoadOpString(Desc.loadOp), *GetStoreOpString(Desc.storeOp)); + DebugLog += FString::Printf(TEXT("%s\t\t\tLoadStencil=%s, StoreStencil=%s, Initial=%s, Final=%s\n"), Tabs, + *GetLoadOpString(Desc.stencilLoadOp), *GetStoreOpString(Desc.stencilStoreOp), *VulkanRHI::GetImageLayoutString(Desc.initialLayout), *VulkanRHI::GetImageLayoutString(Desc.finalLayout)); + } + + for (uint32 Index = 0; Index < CreateInfo->subpassCount; ++Index) + { + const VkSubpassDescription& Desc = CreateInfo->pSubpasses[Index]; + DebugLog += FString::Printf(TEXT("%s\t\tSubpass[%d]: Flags=%d, Bind=%s, NumInputAttach=%d, InputAttach=%p, NumColorAttach=%d, ColorAttach=%p, DSAttch=%p\n"), Tabs, Index, + Desc.flags, + Desc.pipelineBindPoint == VK_PIPELINE_BIND_POINT_COMPUTE ? TEXT("Compute") : TEXT("Gfx"), + Desc.inputAttachmentCount, Desc.pInputAttachments, Desc.colorAttachmentCount, Desc.pColorAttachments, Desc.pDepthStencilAttachment); + for (uint32 SubIndex = 0; SubIndex < Desc.inputAttachmentCount; ++SubIndex) + { + DebugLog += FString::Printf(TEXT("%s\t\t\tInputAttach[%d]: Attach=%d, Layout=%s\n"), Tabs, Index, + Desc.pInputAttachments[SubIndex].attachment, *GetImageLayoutString(Desc.pInputAttachments[SubIndex].layout)); + } + for (uint32 SubIndex = 0; SubIndex < Desc.inputAttachmentCount; ++SubIndex) + { + DebugLog += FString::Printf(TEXT("%s\t\t\tColorAttach[%d]: Attach=%d, Layout=%s\n"), Tabs, Index, + Desc.pColorAttachments[SubIndex].attachment, *GetImageLayoutString(Desc.pColorAttachments[SubIndex].layout)); + } + if (Desc.pDepthStencilAttachment) + { + DebugLog += FString::Printf(TEXT("%s\t\t\tDSAttach: Attach=%d, Layout=%s\n"), Tabs, Desc.pDepthStencilAttachment->attachment, *GetImageLayoutString(Desc.pDepthStencilAttachment->layout)); + } + /* + typedef struct VkAttachmentReference { + uint32_t attachment; + VkImageLayout layout; + } VkAttachmentReference; + + typedef struct VkSubpassDescription { + const VkAttachmentReference* pResolveAttachments; + uint32_t preserveAttachmentCount; + const uint32_t* pPreserveAttachments; + } VkSubpassDescription;*/ + } + +/* + typedef struct VkRenderPassCreateInfo { + uint32_t attachmentCount; + const VkAttachmentDescription* pAttachments; + uint32_t subpassCount; + const VkSubpassDescription* pSubpasses; + uint32_t dependencyCount; + const VkSubpassDependency* pDependencies; + } VkRenderPassCreateInfo; +*/ + + } + } + + void DumpQueueSubmit(VkQueue Queue, uint32 SubmitCount, const VkSubmitInfo* Submits, VkFence Fence) + { + if (CVarVulkanDumpLayer.GetValueOnAnyThread()) + { + PrintfBeginResult(FString::Printf(TEXT("vkQueueSubmit(Queue=%p, Count=%d, Submits=%p, Fence=%p)"), Queue, SubmitCount, Submits, Fence)); + for (uint32 Index = 0; Index < SubmitCount; ++Index) + { + DebugLog += FString::Printf(TEXT("\n%sSubmit[%d]:"), Tabs, Index); + if (Submits[Index].waitSemaphoreCount > 0) + { + DebugLog += FString::Printf(TEXT("\n%s\tWaitSemaphores(Mask): "), Tabs, Index); + for (uint32 SubIndex = 0; SubIndex < Submits[Index].waitSemaphoreCount; ++SubIndex) + { + DebugLog += FString::Printf(TEXT("%p(%d) "), Submits[Index].pWaitSemaphores[SubIndex], (int32)Submits[Index].pWaitDstStageMask[SubIndex]); + } + } + if (Submits[Index].commandBufferCount > 0) + { + DebugLog += FString::Printf(TEXT("\n%s\tCommandBuffers: "), Tabs, Index); + for (uint32 SubIndex = 0; SubIndex < Submits[Index].commandBufferCount; ++SubIndex) + { + DebugLog += FString::Printf(TEXT("%p "), Submits[Index].pCommandBuffers[SubIndex]); + } + } + if (Submits[Index].signalSemaphoreCount > 0) + { + DebugLog += FString::Printf(TEXT("\n%s\tSignalSemaphore: "), Tabs, Index); + for (uint32 SubIndex = 0; SubIndex < Submits[Index].signalSemaphoreCount; ++SubIndex) + { + DebugLog += FString::Printf(TEXT("%p "), Submits[Index].pSignalSemaphores[SubIndex]); + } + } + } + + FlushDebugWrapperLog(); + } + } + + void DumpCreateShaderModule(VkDevice Device, const VkShaderModuleCreateInfo* CreateInfo, VkShaderModule* ShaderModule) + { + DevicePrintfBeginResult(Device, FString::Printf(TEXT("vkCreateShaderModule(CreateInfo=%p, OutShaderModule=%p)[...]"), CreateInfo, ShaderModule)); + } + + void DumpCreatePipelineCache(VkDevice Device, const VkPipelineCacheCreateInfo* CreateInfo, VkPipelineCache* PipelineCache) + { + DevicePrintfBeginResult(Device, FString::Printf(TEXT("vkCreatePipelineCache(CreateInfo=%p, OutPipelineCache=%p)[...]"), CreateInfo, PipelineCache)); + } + + void DumpCreateCommandPool(VkDevice Device, const VkCommandPoolCreateInfo* CreateInfo, VkCommandPool* CommandPool) + { + FlushDebugWrapperLog(); + DevicePrintfBeginResult(Device, FString::Printf(TEXT("vkCreateCommandPool(CreateInfo=%p, OutCommandPool=%p)[...]"), CreateInfo, CommandPool)); + } + + void DumpCreateQueryPool(VkDevice Device, const VkQueryPoolCreateInfo* CreateInfo, VkQueryPool* QueryPool) + { + DevicePrintfBeginResult(Device, FString::Printf(TEXT("vkCreateQueryPool(CreateInfo=%p, OutQueryPool=%p)[...]"), CreateInfo, QueryPool)); + } + + void DumpCreatePipelineLayout(VkDevice Device, const VkPipelineLayoutCreateInfo* CreateInfo, VkPipelineLayout* PipelineLayout) + { + DevicePrintfBeginResult(Device, FString::Printf(TEXT("vkCreatePipelineLayout(CreateInfo=%p, OutPipelineLayout=%p)[...]"), CreateInfo, PipelineLayout)); + } + + void DumpCreateDescriptorPool(VkDevice Device, const VkDescriptorPoolCreateInfo* CreateInfo, VkDescriptorPool* DescriptorPool) + { + DevicePrintfBeginResult(Device, FString::Printf(TEXT("vkCreateDescriptorPool(CreateInfo=%p, OutDescriptorPool=%p)[...]"), CreateInfo, DescriptorPool)); + } + + void DumpCreateSampler(VkDevice Device, const VkSamplerCreateInfo* CreateInfo, VkSampler* Sampler) + { + DevicePrintfBeginResult(Device, FString::Printf(TEXT("vkCreateSampler(CreateInfo=%p, OutSampler=%p)[...]"), CreateInfo, Sampler)); + } + + void DumpCreateDevice(VkPhysicalDevice PhysicalDevice, const VkDeviceCreateInfo* CreateInfo, VkDevice* Device) + { + FlushDebugWrapperLog(); + PrintfBeginResult(FString::Printf(TEXT("vkCreateDevice(PhysicalDevice=%p, CreateInfo=%p, OutDevice=%p)[...]"), PhysicalDevice, CreateInfo, Device)); + } + + void DumpGetPhysicalDeviceFeatures(VkPhysicalDevice PhysicalDevice, VkPhysicalDeviceFeatures* Features) + { + PrintfBeginResult(FString::Printf(TEXT("GetPhysicalDeviceFeatures(PhysicalDevice=%p, Features=%p)[...]"), PhysicalDevice, Features)); + } + + void DumpPhysicalDeviceFeatures(VkPhysicalDeviceFeatures* Features) + { + if (CVarVulkanDumpLayer.GetValueOnAnyThread()) + { + DebugLog += FString::Printf(TEXT("VkPhysicalDeviceFeatures [...]\n")); + } + } + + void DumpBeginCommandBuffer(VkCommandBuffer CommandBuffer, const VkCommandBufferBeginInfo* BeginInfo) + { + FlushDebugWrapperLog(); + + PrintfBeginResult(FString::Printf(TEXT("vkBeginCommandBuffer(CmdBuffer=%p, Info=%p)[...]"), CommandBuffer, BeginInfo)); + } + + void DumpCmdBeginRenderPass(VkCommandBuffer CommandBuffer, const VkRenderPassBeginInfo* RenderPassBegin, VkSubpassContents Contents) + { + if (CVarVulkanDumpLayer.GetValueOnAnyThread()) + { + auto GetSubpassContents = [](VkSubpassContents Contents) -> FString + { + switch (Contents) + { + case VK_SUBPASS_CONTENTS_INLINE: return TEXT("INLINE"); + case VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS: return TEXT("SECONDARY_CMD_BUFS"); + default: return FString::Printf(TEXT("%d"), (int32)Contents); + } + }; + CmdPrintfBegin(CommandBuffer, FString::Printf(TEXT("vkCmdBeginRenderPass(BeginInfo=%p, Contents=%s)"), RenderPassBegin, *GetSubpassContents(Contents))); + DebugLog += FString::Printf(TEXT("%sBeginInfo: RenderPass=%p, Framebuffer=%p, renderArea=(x:%d, y:%d, %s), clearValues=%d\n"), + Tabs, RenderPassBegin->renderPass, RenderPassBegin->framebuffer, + RenderPassBegin->renderArea.offset.x, RenderPassBegin->renderArea.offset.y, + *GetExtentString(RenderPassBegin->renderArea.extent), + RenderPassBegin->clearValueCount); + for (uint32 Index = 0; Index < RenderPassBegin->clearValueCount; ++Index) + { + DebugLog += FString::Printf(TEXT("%s\tclearValue[%d]=(%d(%f), %d(%f), %d(%f), %d(%f))\n"), + Tabs, Index, + RenderPassBegin->pClearValues[Index].color.uint32[0], RenderPassBegin->pClearValues[Index].color.float32[0], + RenderPassBegin->pClearValues[Index].color.uint32[1], RenderPassBegin->pClearValues[Index].color.float32[1], + RenderPassBegin->pClearValues[Index].color.uint32[2], RenderPassBegin->pClearValues[Index].color.float32[2], + RenderPassBegin->pClearValues[Index].color.uint32[3], RenderPassBegin->pClearValues[Index].color.float32[3]); + } + } + } + + void DumpCmdBindVertexBuffers(VkCommandBuffer CommandBuffer, uint32 FirstBinding, uint32 BindingCount, const VkBuffer* Buffers, const VkDeviceSize* Offsets) + { + CmdPrintfBegin(CommandBuffer, FString::Printf(TEXT("vkCmdBindVertexBuffers(FirstBinding=%d, NumBindings=%d, Buffers=%p, Offsets=%p)[...]"), FirstBinding, BindingCount, Buffers, Offsets)); + } + + void DumpCmdCopyBufferToImage(VkCommandBuffer CommandBuffer, VkBuffer SrcBuffer, VkImage DstImage, VkImageLayout DstImageLayout, uint32 RegionCount, const VkBufferImageCopy* Regions) + { + CmdPrintfBegin(CommandBuffer, FString::Printf(TEXT("vkCmdCopyBufferToImage(SrcBuffer=%p, DstImage=%p, DstImageLayout=%s, NumRegions=%d, Regions=%p)[...]"), + SrcBuffer, DstImage, *GetImageLayoutString(DstImageLayout), RegionCount, Regions)); + } + + void DumpCmdCopyBuffer(VkCommandBuffer CommandBuffer, VkBuffer SrcBuffer, VkBuffer DstBuffer, uint32 RegionCount, const VkBufferCopy* Regions) + { + CmdPrintfBegin(CommandBuffer, FString::Printf(TEXT("vkCmdCopyBuffer(SrcBuffer=%p, DstBuffer=%p, NumRegions=%d, Regions=%p)[...]"), SrcBuffer, DstBuffer, RegionCount, Regions)); + } + + void DumpGetImageSubresourceLayout(VkDevice Device, VkImage Image, const VkImageSubresource* Subresource, VkSubresourceLayout* Layout) + { + DevicePrintfBeginResult(Device, FString::Printf(TEXT("vkGetImageSubresourceLayout(Image=%p, Subresource=%p, OutLayout=%p)"), Image, Subresource, Layout)); + } + + void DumpImageSubresourceLayout(VkSubresourceLayout* Layout) + { + if (CVarVulkanDumpLayer.GetValueOnAnyThread()) + { + DebugLog += FString::Printf(TEXT("VkSubresourceLayout: [...]\n")); + } + } + + void DumpSwapChainImages(VkResult Result, uint32* SwapchainImageCount, VkImage* SwapchainImages) + { + if (CVarVulkanDumpLayer.GetValueOnAnyThread()) + { + PrintResult(Result); + if (SwapchainImages) + { + for (uint32 Index = 0; Index < *SwapchainImageCount; ++Index) + { + DebugLog += FString::Printf(TEXT("%sImage[%d]=%p\n"), Tabs, Index, SwapchainImages[Index]); + } + } + else + { + DebugLog += FString::Printf(TEXT("%sNumImages=%d\n"), Tabs, *SwapchainImageCount); + } + } + } + + static struct FGlobalDumpLog + { + ~FGlobalDumpLog() + { + FlushDebugWrapperLog(); + } + } GGlobalDumpLogInstance; +} +#endif // VULKAN_ENABLE_DUMP_LAYER +#endif // VULKAN_HAS_DEBUGGING_ENABLED diff --git a/Engine/Source/Runtime/VulkanRHI/Private/VulkanDevice.cpp b/Engine/Source/Runtime/VulkanRHI/Private/VulkanDevice.cpp index 834782e74748..366fbf18d48b 100644 --- a/Engine/Source/Runtime/VulkanRHI/Private/VulkanDevice.cpp +++ b/Engine/Source/Runtime/VulkanRHI/Private/VulkanDevice.cpp @@ -215,6 +215,9 @@ void FVulkanDevice::SetupFormats() MapFormatSupport(PF_R32_UINT, VK_FORMAT_R32_UINT); SetComponentMapping(PF_R32_UINT, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ZERO); + MapFormatSupport(PF_R8_UINT, VK_FORMAT_R8_UINT); + SetComponentMapping(PF_R8_UINT, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ZERO); + #if PLATFORM_ANDROID MapFormatSupport(PF_D24, VK_FORMAT_X8_D24_UNORM_PACK32); #elif PLATFORM_DESKTOP diff --git a/Engine/Source/Runtime/VulkanRHI/Private/VulkanLayers.cpp b/Engine/Source/Runtime/VulkanRHI/Private/VulkanLayers.cpp index 9097428259fe..276149b94cdf 100644 --- a/Engine/Source/Runtime/VulkanRHI/Private/VulkanLayers.cpp +++ b/Engine/Source/Runtime/VulkanRHI/Private/VulkanLayers.cpp @@ -25,22 +25,30 @@ static const ANSICHAR* GRequiredLayersInstance[] = "VK_LAYER_LUNARG_swapchain", }; +#define VULKAN_ENABLE_STANDARD_VALIDATION 1 + // List of validation layers which we want to activate for the instance static const ANSICHAR* GValidationLayersInstance[] = { #if VULKAN_ENABLE_API_DUMP "VK_LAYER_LUNARG_api_dump", #endif - "VK_LAYER_LUNARG_core_validation", - "VK_LAYER_LUNARG_device_limits", - "VK_LAYER_LUNARG_image", - "VK_LAYER_LUNARG_object_tracker", // The framebuffer is not registered for some reason by the object tracker... the steps are exactly the same as in the demo. For now ObjectTracker is disabled... - "VK_LAYER_LUNARG_parameter_validation", - //"VK_LAYER_LUNARG_screenshot", - "VK_LAYER_GOOGLE_threading", - "VK_LAYER_GOOGLE_unique_objects", - //"VK_LAYER_NV_optimus", + +#if VULKAN_ENABLE_STANDARD_VALIDATION "VK_LAYER_LUNARG_standard_validation", +#else + "VK_LAYER_GOOGLE_threading", + "VK_LAYER_LUNARG_parameter_validation", + "VK_LAYER_LUNARG_object_tracker", + "VK_LAYER_LUNARG_image", + "VK_LAYER_LUNARG_core_validation", + "VK_LAYER_LUNARG_swapchain", + "VK_LAYER_GOOGLE_unique_objects", +#endif + + "VK_LAYER_LUNARG_device_limits", + //"VK_LAYER_LUNARG_screenshot", + //"VK_LAYER_NV_optimus", //"VK_LAYER_LUNARG_vktrace", // Useful for future }; @@ -56,16 +64,22 @@ static const ANSICHAR* GValidationLayersDevice[] = #if VULKAN_ENABLE_API_DUMP "VK_LAYER_LUNARG_api_dump", #endif - "VK_LAYER_LUNARG_core_validation", - "VK_LAYER_LUNARG_device_limits", - "VK_LAYER_LUNARG_image", - "VK_LAYER_LUNARG_object_tracker", // The framebuffer is not registered for some reason by the object tracker... the steps are exactly the same as in the demo. For now ObjectTracker is disabled... - "VK_LAYER_LUNARG_parameter_validation", - //"VK_LAYER_LUNARG_screenshot", - "VK_LAYER_GOOGLE_threading", - "VK_LAYER_GOOGLE_unique_objects", - //"VK_LAYER_NV_optimus", + +#if VULKAN_ENABLE_STANDARD_VALIDATION "VK_LAYER_LUNARG_standard_validation", +#else + "VK_LAYER_GOOGLE_threading", + "VK_LAYER_LUNARG_parameter_validation", + "VK_LAYER_LUNARG_object_tracker", + "VK_LAYER_LUNARG_image", + "VK_LAYER_LUNARG_core_validation", + "VK_LAYER_LUNARG_swapchain", + "VK_LAYER_GOOGLE_unique_objects", +#endif + + "VK_LAYER_LUNARG_device_limits", + //"VK_LAYER_LUNARG_screenshot", + //"VK_LAYER_NV_optimus", //"VK_LAYER_LUNARG_vktrace", // Useful for future }; #endif // VULKAN_HAS_DEBUGGING_ENABLED diff --git a/Engine/Source/Runtime/VulkanRHI/Private/VulkanPendingState.cpp b/Engine/Source/Runtime/VulkanRHI/Private/VulkanPendingState.cpp index 3f96f5227764..008cb0726f40 100644 --- a/Engine/Source/Runtime/VulkanRHI/Private/VulkanPendingState.cpp +++ b/Engine/Source/Runtime/VulkanRHI/Private/VulkanPendingState.cpp @@ -370,7 +370,17 @@ bool FVulkanPendingState::RenderPassBegin(FVulkanCmdBuffer* CmdBuffer) if (RTInfo.DepthStencilRenderTarget.Texture) { VkClearValue& DstColor = ClearValues[Index]; - RTInfo.DepthStencilRenderTarget.Texture->GetClearBinding().GetDepthStencil(DstColor.depthStencil.depth, DstColor.depthStencil.stencil); + const FClearValueBinding& ClearBinding = RTInfo.DepthStencilRenderTarget.Texture->GetClearBinding(); + if (ClearBinding.ColorBinding == EClearBinding::EDepthStencilBound) + { + ClearBinding.GetDepthStencil(DstColor.depthStencil.depth, DstColor.depthStencil.stencil); + } + else + { + ensure(!RTInfo.bClearDepth && !RTInfo.bClearStencil); + DstColor.depthStencil.depth = 1.0f; + DstColor.depthStencil.stencil = 0; + } // @todo vulkan - we don't track the format of the depth buffer in the key, only if depth is enabled (write/test) - should be enough, but worth checking that // if either bit is set that we have a depth buffer attached } diff --git a/Engine/Source/Runtime/VulkanRHI/Private/VulkanQuery.cpp b/Engine/Source/Runtime/VulkanRHI/Private/VulkanQuery.cpp index 39eb98ca0807..d18dbc774852 100644 --- a/Engine/Source/Runtime/VulkanRHI/Private/VulkanQuery.cpp +++ b/Engine/Source/Runtime/VulkanRHI/Private/VulkanQuery.cpp @@ -53,7 +53,9 @@ FVulkanTimestampQueryPool::FVulkanTimestampQueryPool(FVulkanDevice* InDevice) : TimeStampsPerSeconds(0), SecondsPerTimestamp(0), UsedUserQueries(0), - bFirst(true) + bFirst(true), + LastEndCmdBuffer(nullptr), + LastFenceSignaledCounter(0) { // The number of nanoseconds it takes for a timestamp value to be incremented by 1 can be obtained from VkPhysicalDeviceLimits::timestampPeriod after a call to vkGetPhysicalDeviceProperties. double NanoSecondsPerTimestamp = Device->GetDeviceProperties().limits.timestampPeriod; @@ -76,12 +78,14 @@ void FVulkanTimestampQueryPool::WriteStartFrame(VkCommandBuffer CmdBuffer) VulkanRHI::vkCmdWriteTimestamp(CmdBuffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, QueryPool, StartFrame); } -void FVulkanTimestampQueryPool::WriteEndFrame(VkCommandBuffer CmdBuffer) +void FVulkanTimestampQueryPool::WriteEndFrame(FVulkanCmdBuffer* CmdBuffer) { if (!bFirst) { // End Frame Timestamp - VulkanRHI::vkCmdWriteTimestamp(CmdBuffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, QueryPool, EndFrame); + VulkanRHI::vkCmdWriteTimestamp(CmdBuffer->GetHandle(), VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, QueryPool, EndFrame); + LastEndCmdBuffer = CmdBuffer; + LastFenceSignaledCounter = CmdBuffer->GetFenceSignaledCounter(); } } @@ -90,17 +94,25 @@ void FVulkanTimestampQueryPool::CalculateFrameTime() uint64_t Results[2] = { 0, 0 }; if (!bFirst) { - VkDevice DeviceHandle = Device->GetInstanceHandle(); - VkResult Result; - Result = VulkanRHI::vkGetQueryPoolResults(DeviceHandle, QueryPool, StartFrame, 2, sizeof(Results), Results, sizeof(uint64), /*VK_QUERY_RESULT_WAIT_BIT | */VK_QUERY_RESULT_64_BIT); - if (Result != VK_SUCCESS) + if (LastEndCmdBuffer && LastFenceSignaledCounter < LastEndCmdBuffer->GetFenceSignaledCounter()) + { + VkDevice DeviceHandle = Device->GetInstanceHandle(); + VkResult Result; + Result = VulkanRHI::vkGetQueryPoolResults(DeviceHandle, QueryPool, StartFrame, 2, sizeof(Results), Results, sizeof(uint64), /*VK_QUERY_RESULT_PARTIAL_BIT |*/ VK_QUERY_RESULT_64_BIT); + if (Result != VK_SUCCESS) + { + GGPUFrameTime = 0; + return; + } + } + else { - GGPUFrameTime = 0; return; } } - double ValueInSeconds = (double)(Results[1] - Results[0]) * SecondsPerTimestamp; + const uint64 Delta = Results[1] - Results[0]; + double ValueInSeconds = (double)Delta * SecondsPerTimestamp; GGPUFrameTime = (uint32)(ValueInSeconds / FPlatformTime::GetSecondsPerCycle()); } diff --git a/Engine/Source/Runtime/VulkanRHI/Private/VulkanQueue.cpp b/Engine/Source/Runtime/VulkanRHI/Private/VulkanQueue.cpp index a448f92e2ddb..ca2c43825a40 100644 --- a/Engine/Source/Runtime/VulkanRHI/Private/VulkanQueue.cpp +++ b/Engine/Source/Runtime/VulkanRHI/Private/VulkanQueue.cpp @@ -65,7 +65,10 @@ void FVulkanQueue::Submit(FVulkanCmdBuffer* CmdBuffer, FVulkanSemaphore* WaitSem SubmitInfo.pWaitSemaphores = &Semaphores[1]; SubmitInfo.pWaitDstStageMask = &WaitStageFlags; } - VERIFYVULKANRESULT(VulkanRHI::vkQueueSubmit(Queue, 1, &SubmitInfo, Fence->GetHandle())); + { + SCOPE_CYCLE_COUNTER(STAT_VulkanQueueSubmit) + VERIFYVULKANRESULT(VulkanRHI::vkQueueSubmit(Queue, 1, &SubmitInfo, Fence->GetHandle())); + } if (GWaitForIdleOnSubmit != 0) { diff --git a/Engine/Source/Runtime/VulkanRHI/Private/VulkanRHI.cpp b/Engine/Source/Runtime/VulkanRHI/Private/VulkanRHI.cpp index 1472580ba623..223e185febfd 100644 --- a/Engine/Source/Runtime/VulkanRHI/Private/VulkanRHI.cpp +++ b/Engine/Source/Runtime/VulkanRHI/Private/VulkanRHI.cpp @@ -45,7 +45,7 @@ static TAutoConsoleVariable GLSLCvar( static TAutoConsoleVariable GRHIThreadCvar( TEXT("r.Vulkan.RHIThread"), - 0, + 1, TEXT("1 to use RHI Thread") ); diff --git a/Engine/Source/Runtime/VulkanRHI/Private/VulkanRHIPrivate.h b/Engine/Source/Runtime/VulkanRHI/Private/VulkanRHIPrivate.h index ee90726ff251..869a456702fb 100644 --- a/Engine/Source/Runtime/VulkanRHI/Private/VulkanRHIPrivate.h +++ b/Engine/Source/Runtime/VulkanRHI/Private/VulkanRHIPrivate.h @@ -412,6 +412,8 @@ DECLARE_CYCLE_STAT_EXTERN(TEXT("Uniform Buffer Creation Time"), STAT_VulkanUnifo DECLARE_CYCLE_STAT_EXTERN(TEXT("Apply DS Uniform Buffers"), STAT_VulkanApplyDSUniformBuffers, STATGROUP_VulkanRHI, ); DECLARE_CYCLE_STAT_EXTERN(TEXT("SRV Update Time"), STAT_VulkanSRVUpdateTime, STATGROUP_VulkanRHI, ); DECLARE_CYCLE_STAT_EXTERN(TEXT("Deletion Queue"), STAT_VulkanDeletionQueue, STATGROUP_VulkanRHI, ); +DECLARE_CYCLE_STAT_EXTERN(TEXT("Queue Submit"), STAT_VulkanQueueSubmit, STATGROUP_VulkanRHI, ); +DECLARE_CYCLE_STAT_EXTERN(TEXT("Queue Present"), STAT_VulkanQueuePresent, STATGROUP_VulkanRHI, ); #if VULKAN_ENABLE_AGGRESSIVE_STATS DECLARE_CYCLE_STAT_EXTERN(TEXT("Apply DS Shader Resources"), STAT_VulkanApplyDSResources, STATGROUP_VulkanRHI, ); DECLARE_CYCLE_STAT_EXTERN(TEXT("Update DescriptorSets"), STAT_VulkanUpdateDescriptorSets, STATGROUP_VulkanRHI, ); diff --git a/Engine/Source/Runtime/VulkanRHI/Private/VulkanRenderTarget.cpp b/Engine/Source/Runtime/VulkanRHI/Private/VulkanRenderTarget.cpp index 30c78a8e4acf..600a9fdf8f78 100644 --- a/Engine/Source/Runtime/VulkanRHI/Private/VulkanRenderTarget.cpp +++ b/Engine/Source/Runtime/VulkanRHI/Private/VulkanRenderTarget.cpp @@ -38,10 +38,6 @@ void FVulkanCommandListContext::RHISetRenderTargets(uint32 NumSimultaneousRender checkf(NumUAVs == 0, TEXT("Calling SetRenderTargets with UAVs is not supported in Vulkan yet")); } -void FVulkanDynamicRHI::RHIDiscardRenderTargets(bool Depth, bool Stencil, uint32 ColorBitMask) -{ -} - void FVulkanCommandListContext::RHISetRenderTargetsAndClear(const FRHISetRenderTargetsInfo& RenderTargetsInfo) { //FRCLog::Printf(FString::Printf(TEXT("RHISetRenderTargetsAndClear\n"))); @@ -203,7 +199,14 @@ void FVulkanCommandListContext::RHITransitionResources(EResourceTransitionAccess } else { - ensure(0); + FRHITexture3D* RHITexture3D = RHITexture->GetTexture3D(); + if (RHITexture3D) + { + } + else + { + ensure(0); + } } } } diff --git a/Engine/Source/Runtime/VulkanRHI/Private/VulkanShaders.cpp b/Engine/Source/Runtime/VulkanRHI/Private/VulkanShaders.cpp index 4d1338ec849a..8a15942bc1be 100644 --- a/Engine/Source/Runtime/VulkanRHI/Private/VulkanShaders.cpp +++ b/Engine/Source/Runtime/VulkanRHI/Private/VulkanShaders.cpp @@ -235,7 +235,7 @@ FVulkanBoundShaderState::FVulkanBoundShaderState( FMemory::Memzero(VertexInputBindings); FMemory::Memzero(Attributes); FMemory::Memzero(VertexInputStateInfo); - FMemory::Memzero(DescriptorImageInfoForStage); + FMemory::Memzero(DescriptorSamplerImageInfoForStage); static_assert(CrossCompiler::PACKED_TYPEINDEX_MAX <= sizeof(DirtyPackedUniformBufferStagingMask[0]) * 8, "Won't fit!"); FMemory::Memzero(DescriptorBufferInfoForPackedUBForStage); @@ -306,13 +306,13 @@ FVulkanBoundShaderState::FVulkanBoundShaderState( GenerateLayoutBindings(); - uint32 UniformSamplerCount = 0; + uint32 UniformCombinedSamplerCount = 0; uint32 UniformSamplerBufferCount = 0; uint32 UniformBufferCount = 0; - GetDescriptorInfoCounts(UniformSamplerCount, UniformSamplerBufferCount, UniformBufferCount); + GetDescriptorInfoCounts(UniformCombinedSamplerCount, UniformSamplerBufferCount, UniformBufferCount); // Setup Write information - CreateDescriptorWriteInfo(UniformSamplerCount, UniformSamplerBufferCount, UniformBufferCount); + CreateDescriptorWriteInfo(UniformCombinedSamplerCount, UniformSamplerBufferCount, UniformBufferCount); } FVulkanBoundShaderState::~FVulkanBoundShaderState() @@ -533,20 +533,20 @@ void FVulkanBoundShaderState::GenerateLayoutBindings(EShaderFrequency Stage, con } }; - LoopPerType(FVulkanShaderSerializedBindings::TYPE_SAMPLER, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER); + LoopPerType(FVulkanShaderSerializedBindings::TYPE_COMBINED_IMAGE_SAMPLER, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER); LoopPerType(FVulkanShaderSerializedBindings::TYPE_SAMPLER_BUFFER, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER); LoopPerType(FVulkanShaderSerializedBindings::TYPE_UNIFORM_BUFFER, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER); LoopPerType(FVulkanShaderSerializedBindings::TYPE_PACKED_UNIFORM_BUFFER, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER); } -void FVulkanBoundShaderState::CreateDescriptorWriteInfo(uint32 InUniformSamplerCount, uint32 InUniformSamplerBufferCount, uint32 InUniformBufferCount) +void FVulkanBoundShaderState::CreateDescriptorWriteInfo(uint32 InUniformCombinedSamplerCount, uint32 InUniformSamplerBufferCount, uint32 InUniformBufferCount) { check(DescriptorWrites.Num() == 0); - DescriptorWrites.AddZeroed(InUniformSamplerCount + InUniformSamplerBufferCount + InUniformBufferCount); - DescriptorImageInfo.AddZeroed(InUniformSamplerCount); + DescriptorWrites.AddZeroed(InUniformCombinedSamplerCount + InUniformSamplerBufferCount + InUniformBufferCount); + DescriptorImageInfo.AddZeroed(InUniformCombinedSamplerCount); DescriptorBufferInfo.AddZeroed(InUniformBufferCount); - for (uint32 Index = 0; Index < InUniformSamplerCount; ++Index) + for (uint32 Index = 0; Index < InUniformCombinedSamplerCount; ++Index) { VkDescriptorImageInfo& Sampler = DescriptorImageInfo[Index]; // Texture.Load() still requires a default sampler... @@ -574,13 +574,13 @@ void FVulkanBoundShaderState::CreateDescriptorWriteInfo(uint32 InUniformSamplerC //#todo-rco: Use BindingTable instead... auto& Bindings = StageShader->CodeHeader.SerializedBindings.Bindings; - if (InUniformSamplerCount) + if (InUniformCombinedSamplerCount) { - DescriptorImageInfoForStage[Stage] = DescriptorImageInfo.GetData() + ImageIndex; + DescriptorSamplerImageInfoForStage[Stage] = DescriptorImageInfo.GetData() + ImageIndex; - for (int32 Index = 0; Index < Bindings[FVulkanShaderSerializedBindings::TYPE_SAMPLER].Num(); ++Index) + for (int32 Index = 0; Index < Bindings[FVulkanShaderSerializedBindings::TYPE_COMBINED_IMAGE_SAMPLER].Num(); ++Index) { - FVulkanShaderSerializedBindings::FBindMap& Mapping = Bindings[FVulkanShaderSerializedBindings::TYPE_SAMPLER][Index]; + FVulkanShaderSerializedBindings::FBindMap& Mapping = Bindings[FVulkanShaderSerializedBindings::TYPE_COMBINED_IMAGE_SAMPLER][Index]; VkWriteDescriptorSet* WriteDesc = &DescriptorWrites[WriteIndex++]; WriteDesc->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; WriteDesc->dstBinding = Mapping.VulkanBindingIndex; @@ -635,7 +635,7 @@ void FVulkanBoundShaderState::CreateDescriptorWriteInfo(uint32 InUniformSamplerC } } - check(InUniformSamplerCount + InUniformSamplerBufferCount + InUniformBufferCount == DescriptorWrites.Num()); + check(InUniformCombinedSamplerCount + InUniformSamplerBufferCount + InUniformBufferCount == DescriptorWrites.Num()); } void FVulkanBoundShaderState::InternalBindVertexStreams(FVulkanCmdBuffer* Cmd, const void* InVertexStreams) @@ -919,8 +919,8 @@ void FVulkanBoundShaderState::SetTexture(EShaderFrequency Stage, uint32 BindPoin check(VulkanTextureBase); FVulkanShader* StageShader = GetShaderPtr((EShaderFrequency)Stage); - uint32 VulkanBindingPoint = StageShader->GetBindingTable().SamplerBindingIndices[BindPoint]; - DescriptorImageInfoForStage[Stage][VulkanBindingPoint].imageView = VulkanTextureBase ? VulkanTextureBase->View.View : VK_NULL_HANDLE; + uint32 VulkanBindingPoint = StageShader->GetBindingTable().CombinedSamplerBindingIndices[BindPoint]; + DescriptorSamplerImageInfoForStage[Stage][VulkanBindingPoint].imageView = VulkanTextureBase ? VulkanTextureBase->View.View : VK_NULL_HANDLE; DirtyTextures[Stage] = true; #if VULKAN_ENABLE_RHI_DEBUGGING @@ -937,8 +937,8 @@ void FVulkanBoundShaderState::SetSamplerState(EShaderFrequency Stage, uint32 Bin #endif FVulkanShader* StageShader = GetShaderPtr((EShaderFrequency)Stage); - uint32 VulkanBindingPoint = StageShader->GetBindingTable().SamplerBindingIndices[BindPoint]; - DescriptorImageInfoForStage[Stage][VulkanBindingPoint].sampler = Sampler ? Sampler->Sampler : VK_NULL_HANDLE; + uint32 VulkanBindingPoint = StageShader->GetBindingTable().CombinedSamplerBindingIndices[BindPoint]; + DescriptorSamplerImageInfoForStage[Stage][VulkanBindingPoint].sampler = Sampler ? Sampler->Sampler : VK_NULL_HANDLE; DirtySamplerStates[Stage] = true; #if VULKAN_ENABLE_RHI_DEBUGGING @@ -1018,9 +1018,9 @@ void FVulkanBoundShaderState::SetUniformBuffer(FVulkanPendingState& PendingState #endif } -void FVulkanBoundShaderState::GetDescriptorInfoCounts(uint32& OutSamplerCount, uint32& OutSamplerBufferCount, uint32& OutUniformBufferCount) +void FVulkanBoundShaderState::GetDescriptorInfoCounts(uint32& OutCombinedSamplerCount, uint32& OutSamplerBufferCount, uint32& OutUniformBufferCount) { - OutSamplerCount = 0; + OutCombinedSamplerCount = 0; OutSamplerBufferCount = 0; OutUniformBufferCount = 0; @@ -1033,7 +1033,7 @@ void FVulkanBoundShaderState::GetDescriptorInfoCounts(uint32& OutSamplerCount, u { auto& Layouts = StageShader->CodeHeader.SerializedBindings.Bindings; - OutSamplerCount += Layouts[FVulkanShaderSerializedBindings::TYPE_SAMPLER].Num(); + OutCombinedSamplerCount += Layouts[FVulkanShaderSerializedBindings::TYPE_COMBINED_IMAGE_SAMPLER].Num(); OutSamplerBufferCount += Layouts[FVulkanShaderSerializedBindings::TYPE_SAMPLER_BUFFER].Num(); OutUniformBufferCount += Layouts[FVulkanShaderSerializedBindings::TYPE_PACKED_UNIFORM_BUFFER].Num() + Layouts[FVulkanShaderSerializedBindings::TYPE_UNIFORM_BUFFER].Num(); diff --git a/Engine/Source/Runtime/VulkanRHI/Private/VulkanSwapChain.cpp b/Engine/Source/Runtime/VulkanRHI/Private/VulkanSwapChain.cpp index 3522df42f0c5..b5073224753a 100644 --- a/Engine/Source/Runtime/VulkanRHI/Private/VulkanSwapChain.cpp +++ b/Engine/Source/Runtime/VulkanRHI/Private/VulkanSwapChain.cpp @@ -221,7 +221,10 @@ bool FVulkanSwapChain::Present(FVulkanQueue* Queue, FVulkanSemaphore* BackBuffer Info.pSwapchains = &SwapChain; Info.pImageIndices = (uint32*)&CurrentImageIndex; - VERIFYVULKANRESULT(VulkanRHI::vkQueuePresentKHR(Queue->GetHandle(), &Info)); + { + SCOPE_CYCLE_COUNTER(STAT_VulkanQueuePresent); + VERIFYVULKANRESULT(VulkanRHI::vkQueuePresentKHR(Queue->GetHandle(), &Info)); + } return true; } diff --git a/Engine/Source/Runtime/VulkanRHI/Private/VulkanTexture.cpp b/Engine/Source/Runtime/VulkanRHI/Private/VulkanTexture.cpp index 2f3a4c06a733..e26324a6ae06 100644 --- a/Engine/Source/Runtime/VulkanRHI/Private/VulkanTexture.cpp +++ b/Engine/Source/Runtime/VulkanRHI/Private/VulkanTexture.cpp @@ -1223,7 +1223,17 @@ void FVulkanDynamicRHI::RHIBindDebugLabelName(FTextureRHIParamRef TextureRHI, co FVulkanTexture2D* VTex2d = (FVulkanTexture2D*)Tex2d; VulkanRHI::PrintfBegin(FString::Printf(TEXT("vkDebugMarkerSetObjectNameEXT(%p=%s)"), VTex2d->Surface.Image, Name)); } - } + else if (FRHITextureCube* TexCube = TextureRHI->GetTextureCube()) + { + FVulkanTextureCube* VTexCube = (FVulkanTextureCube*)TexCube; + VulkanRHI::PrintfBegin(FString::Printf(TEXT("vkDebugMarkerSetObjectNameEXT(%p=%s)"), VTexCube->Surface.Image, Name)); + } + else if (FRHITexture3D* Tex3d = TextureRHI->GetTexture3D()) + { + FVulkanTexture3D* VTex3d = (FVulkanTexture3D*)Tex3d; + VulkanRHI::PrintfBegin(FString::Printf(TEXT("vkDebugMarkerSetObjectNameEXT(%p=%s)"), VTex3d->Surface.Image, Name)); + } +} #endif #if VULKAN_ENABLE_DRAW_MARKERS diff --git a/Engine/Source/Runtime/VulkanRHI/Private/VulkanUtil.cpp b/Engine/Source/Runtime/VulkanRHI/Private/VulkanUtil.cpp index deb08e789d62..b3e892204079 100644 --- a/Engine/Source/Runtime/VulkanRHI/Private/VulkanUtil.cpp +++ b/Engine/Source/Runtime/VulkanRHI/Private/VulkanUtil.cpp @@ -463,6 +463,8 @@ DEFINE_STAT(STAT_VulkanUniformBufferCreateTime); DEFINE_STAT(STAT_VulkanApplyDSUniformBuffers); DEFINE_STAT(STAT_VulkanSRVUpdateTime); DEFINE_STAT(STAT_VulkanDeletionQueue); +DEFINE_STAT(STAT_VulkanQueueSubmit); +DEFINE_STAT(STAT_VulkanQueuePresent); #if VULKAN_ENABLE_AGGRESSIVE_STATS DEFINE_STAT(STAT_VulkanApplyDSResources); DEFINE_STAT(STAT_VulkanUpdateDescriptorSets); diff --git a/Engine/Source/Runtime/VulkanRHI/Private/VulkanViewport.cpp b/Engine/Source/Runtime/VulkanRHI/Private/VulkanViewport.cpp index 5fc9afb00c9d..defe13ad45c6 100644 --- a/Engine/Source/Runtime/VulkanRHI/Private/VulkanViewport.cpp +++ b/Engine/Source/Runtime/VulkanRHI/Private/VulkanViewport.cpp @@ -369,6 +369,21 @@ bool FVulkanViewport::Present(FVulkanCmdBuffer* CmdBuffer, FVulkanQueue* Queue, //#todo-rco: Might need to NOT be undefined... VulkanSetImageLayoutSimple(CmdBuffer->GetHandle(), BackBufferImages[AcquiredImageIndex], VK_IMAGE_LAYOUT_UNDEFINED/*VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL*/, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); + + { + FVulkanTimestampQueryPool* TimestampPool = Device->GetTimestampQueryPool(PresentCount % FVulkanDevice::NumTimestampPools); + if (TimestampPool) + { + TimestampPool->WriteEndFrame(CmdBuffer); + } + + if (PresentCount >= FVulkanDevice::NumTimestampPools) + { + FVulkanTimestampQueryPool* PrevTimestampPool = Device->GetTimestampQueryPool((PresentCount + FVulkanDevice::NumTimestampPools - 1) % FVulkanDevice::NumTimestampPools); + PrevTimestampPool->CalculateFrameTime(); + } + } + CmdBuffer->End(); Queue->Submit(CmdBuffer, nullptr, 0, RenderingDoneSemaphores[AcquiredImageIndex]); @@ -420,7 +435,8 @@ bool FVulkanViewport::Present(FVulkanCmdBuffer* CmdBuffer, FVulkanQueue* Queue, //#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(); - Device->GetImmediateContext().GetCommandBufferManager()->PrepareForNewActiveCommandBuffer(); + FVulkanCommandBufferManager* ImmediateCmdBufMgr = Device->GetImmediateContext().GetCommandBufferManager(); + ImmediateCmdBufMgr->PrepareForNewActiveCommandBuffer(); //#todo-rco: Consolidate 'end of frame' Device->GetImmediateContext().GetTempFrameAllocationBuffer().Reset(); @@ -444,6 +460,15 @@ bool FVulkanViewport::Present(FVulkanCmdBuffer* CmdBuffer, FVulkanQueue* Queue, } #endif ++PresentCount; + { + FVulkanTimestampQueryPool* TimestampPool = Device->GetTimestampQueryPool(PresentCount % FVulkanDevice::NumTimestampPools); + if (TimestampPool) + { + FVulkanCmdBuffer* ActiveCmdBuffer = ImmediateCmdBufMgr->GetActiveCmdBuffer(); + TimestampPool->WriteStartFrame(ActiveCmdBuffer->GetHandle()); + } + } + return bResult; } @@ -476,11 +501,12 @@ void FVulkanDynamicRHI::RHIResizeViewport(FViewportRHIParamRef ViewportRHI, uint FVulkanViewport* Viewport = ResourceCast(ViewportRHI); } -void FVulkanDynamicRHI::RHITick( float DeltaTime ) +void FVulkanDynamicRHI::RHITick(float DeltaTime) { - check( IsInGameThread() ); + check(IsInGameThread()); } +/* void FVulkanDynamicRHI::WriteEndFrameTimestamp(void* Data) { FVulkanDynamicRHI* This = (FVulkanDynamicRHI*)Data; @@ -496,6 +522,7 @@ void FVulkanDynamicRHI::WriteEndFrameTimestamp(void* Data) VulkanRHI::GManager.GPUProfilingData.EndFrameBeforeSubmit(); } +*/ #if 0 void FVulkanDynamicRHI::Present() diff --git a/Engine/Source/Runtime/VulkanRHI/Public/VulkanRHI.h b/Engine/Source/Runtime/VulkanRHI/Public/VulkanRHI.h index 96506d9aa602..e70627bf03f3 100644 --- a/Engine/Source/Runtime/VulkanRHI/Public/VulkanRHI.h +++ b/Engine/Source/Runtime/VulkanRHI/Public/VulkanRHI.h @@ -123,7 +123,7 @@ public: virtual void RHIResizeViewport(FViewportRHIParamRef Viewport, uint32 SizeX, uint32 SizeY, bool bIsFullscreen) final override; virtual void RHITick(float DeltaTime) final override; virtual void RHISetStreamOutTargets(uint32 NumTargets,const FVertexBufferRHIParamRef* VertexBuffers,const uint32* Offsets) final override; - virtual void RHIDiscardRenderTargets(bool Depth,bool Stencil,uint32 ColorBitMask) final override; + virtual void RHIDiscardRenderTargets(bool Depth,bool Stencil,uint32 ColorBitMask) final override {} virtual void RHIBlockUntilGPUIdle() final override; virtual void RHISuspendRendering() final override; virtual void RHIResumeRendering() final override; @@ -179,7 +179,9 @@ protected: friend class FVulkanViewport; +/* static void WriteEndFrameTimestamp(void*); +*/ static void GetInstanceLayersAndExtensions(TArray& OutInstanceExtensions, TArray& OutInstanceLayers); diff --git a/Engine/Source/Runtime/VulkanRHI/Public/VulkanResources.h b/Engine/Source/Runtime/VulkanRHI/Public/VulkanResources.h index 31771f230da2..1fd4903bf035 100644 --- a/Engine/Source/Runtime/VulkanRHI/Public/VulkanResources.h +++ b/Engine/Source/Runtime/VulkanRHI/Public/VulkanResources.h @@ -523,7 +523,7 @@ public: virtual ~FVulkanTimestampQueryPool(){} void WriteStartFrame(VkCommandBuffer CmdBuffer); - void WriteEndFrame(VkCommandBuffer CmdBuffer); + void WriteEndFrame(FVulkanCmdBuffer* CmdBuffer); void CalculateFrameTime(); @@ -551,6 +551,9 @@ protected: double SecondsPerTimestamp; int32 UsedUserQueries; bool bFirst; + + FVulkanCmdBuffer* LastEndCmdBuffer; + uint64 LastFenceSignaledCounter; }; /** Vulkan occlusion query */ @@ -981,7 +984,7 @@ private: void GenerateVertexInputStateInfo(); - void GetDescriptorInfoCounts(uint32& OutSamplerCount, uint32& OutSamplerBufferCount, uint32& OutUniformBufferCount); + void GetDescriptorInfoCounts(uint32& OutCombinedSamplerCount, uint32& OutSamplerBufferCount, uint32& OutUniformBufferCount); void InternalBindVertexStreams(FVulkanCmdBuffer* Cmd, const void* VertexStreams); @@ -1030,7 +1033,7 @@ private: // At this moment unused, the samplers are mapped together with texture/image // we are using "VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER" bool DirtySamplerStates[SF_Compute]; - VkDescriptorImageInfo* DescriptorImageInfoForStage[SF_Compute]; + VkDescriptorImageInfo* DescriptorSamplerImageInfoForStage[SF_Compute]; TArray< VkWriteDescriptorSet* > SRVWriteInfoForStage[SF_Compute]; bool DirtySRVs[SF_Compute]; @@ -1051,7 +1054,7 @@ private: // InOutMask is used from VertexShader-Header to filter out active attributs void ProcessVertexElementForBinding(const FVertexElement& Element); - void CreateDescriptorWriteInfo(uint32 UniformSamplerCount, uint32 UniformSamplerBufferCount, uint32 UniformBufferCount); + void CreateDescriptorWriteInfo(uint32 UniformCombinedSamplerCount, uint32 UniformSamplerBufferCount, uint32 UniformBufferCount); uint32 BindingsNum; uint32 BindingsMask; diff --git a/Engine/Source/Runtime/VulkanRHI/Public/VulkanShaderResources.h b/Engine/Source/Runtime/VulkanRHI/Public/VulkanShaderResources.h index 3652b4cb9ff6..a36e811505af 100644 --- a/Engine/Source/Runtime/VulkanRHI/Public/VulkanShaderResources.h +++ b/Engine/Source/Runtime/VulkanRHI/Public/VulkanShaderResources.h @@ -73,10 +73,12 @@ public: enum EBindingType : uint16 { - TYPE_SAMPLER, + TYPE_COMBINED_IMAGE_SAMPLER, TYPE_SAMPLER_BUFFER, TYPE_UNIFORM_BUFFER, TYPE_PACKED_UNIFORM_BUFFER, + //TYPE_SAMPLER, + //TYPE_IMAGE, TYPE_MAX, }; @@ -180,7 +182,7 @@ inline FArchive& operator<<(FArchive& Ar, FVulkanCodeHeader& Header) class FVulkanShaderBindingTable { public: - TArray SamplerBindingIndices; + TArray CombinedSamplerBindingIndices; //#todo-rco: FIX! SamplerBuffers share numbering with Samplers TArray SamplerBufferBindingIndices; TArray UniformBufferBindingIndices; @@ -199,7 +201,7 @@ public: inline FArchive& operator<<(FArchive& Ar, FVulkanShaderBindingTable& BindingTable) { - Ar << BindingTable.SamplerBindingIndices; + Ar << BindingTable.CombinedSamplerBindingIndices; Ar << BindingTable.SamplerBufferBindingIndices; Ar << BindingTable.UniformBufferBindingIndices; for (int32 Index = 0; Index < CrossCompiler::PACKED_TYPEINDEX_MAX; ++Index) diff --git a/Engine/Source/Runtime/Windows/D3D11RHI/Private/D3D11Device.cpp b/Engine/Source/Runtime/Windows/D3D11RHI/Private/D3D11Device.cpp index 1feec13634bc..74452d30e7b7 100644 --- a/Engine/Source/Runtime/Windows/D3D11RHI/Private/D3D11Device.cpp +++ b/Engine/Source/Runtime/Windows/D3D11RHI/Private/D3D11Device.cpp @@ -167,6 +167,7 @@ FD3D11DynamicRHI::FD3D11DynamicRHI(IDXGIFactory1* InDXGIFactory1,D3D_FEATURE_LEV GPixelFormats[ PF_BC6H ].PlatformFormat = DXGI_FORMAT_BC6H_UF16; GPixelFormats[ PF_BC7 ].PlatformFormat = DXGI_FORMAT_BC7_TYPELESS; + GPixelFormats[ PF_R8_UINT ].PlatformFormat = DXGI_FORMAT_R8_UINT; if (FeatureLevel >= D3D_FEATURE_LEVEL_11_0) { @@ -469,6 +470,14 @@ void FD3D11DynamicRHI::CleanupD3DDevice() { Direct3DDeviceIMContext->ClearState(); Direct3DDeviceIMContext->Flush(); + + // Perform a detailed live object report (with resource types) + ID3D11Debug* D3D11Debug; + Direct3DDevice->QueryInterface(__uuidof(ID3D11Debug), (void**)(&D3D11Debug)); + if (D3D11Debug) + { + D3D11Debug->ReportLiveDeviceObjects(D3D11_RLDO_DETAIL); + } } Direct3DDeviceIMContext = nullptr; diff --git a/Engine/Source/Runtime/Windows/D3D12RHI/Private/D3D12Commands.cpp b/Engine/Source/Runtime/Windows/D3D12RHI/Private/D3D12Commands.cpp index 704b375ada64..92ac7a7f34f6 100644 --- a/Engine/Source/Runtime/Windows/D3D12RHI/Private/D3D12Commands.cpp +++ b/Engine/Source/Runtime/Windows/D3D12RHI/Private/D3D12Commands.cpp @@ -1221,6 +1221,7 @@ void FD3D12CommandContext::RHIBeginRenderQuery(FRenderQueryRHIParamRef QueryRHI) { Query->bResultIsCached = false; Query->HeapIndex = GetParentDevice()->GetQueryHeap()->BeginQuery(*this, D3D12_QUERY_TYPE_OCCLUSION); + Query->OwningContext = this; } else { @@ -1251,6 +1252,7 @@ void FD3D12CommandContext::RHIEndRenderQuery(FRenderQueryRHIParamRef QueryRHI) Query->CLSyncPoint = CommandListHandle; CommandListHandle.UpdateResidency(pQueryHeap->GetResultBuffer()); + check(Query->OwningContext == this); break; } @@ -1258,6 +1260,7 @@ void FD3D12CommandContext::RHIEndRenderQuery(FRenderQueryRHIParamRef QueryRHI) { Query->bResultIsCached = false; Query->CLSyncPoint = CommandListHandle; + Query->OwningContext = this; this->otherWorkCounter += 2; // +2 For the EndQuery and the ResolveQueryData CommandListHandle->EndQuery(Query->QueryHeap, D3D12_QUERY_TYPE_TIMESTAMP, Query->HeapIndex); CommandListHandle->ResolveQueryData(Query->QueryHeap, D3D12_QUERY_TYPE_TIMESTAMP, Query->HeapIndex, 1, Query->ResultBuffer, sizeof(uint64) * Query->HeapIndex); diff --git a/Engine/Source/Runtime/Windows/D3D12RHI/Private/D3D12Device.cpp b/Engine/Source/Runtime/Windows/D3D12RHI/Private/D3D12Device.cpp index 708aa2d061c0..a082a24b7260 100644 --- a/Engine/Source/Runtime/Windows/D3D12RHI/Private/D3D12Device.cpp +++ b/Engine/Source/Runtime/Windows/D3D12RHI/Private/D3D12Device.cpp @@ -438,6 +438,7 @@ FD3D12DynamicRHI::FD3D12DynamicRHI(IDXGIFactory4* InDXGIFactory, FD3D12Adapter& GPixelFormats[ PF_BC6H ].PlatformFormat = DXGI_FORMAT_BC6H_UF16; GPixelFormats[ PF_BC7 ].PlatformFormat = DXGI_FORMAT_BC7_TYPELESS; + GPixelFormats[ PF_R8_UINT ].PlatformFormat = DXGI_FORMAT_R8_UINT; // MS - Not doing any feature level checks. D3D12 currently supports these limits. // However this may need to be revisited if new feature levels are introduced with different HW requirement diff --git a/Engine/Source/Runtime/Windows/D3D12RHI/Private/D3D12Query.cpp b/Engine/Source/Runtime/Windows/D3D12RHI/Private/D3D12Query.cpp index 6fdd9330db04..2d705d637acc 100644 --- a/Engine/Source/Runtime/Windows/D3D12RHI/Private/D3D12Query.cpp +++ b/Engine/Source/Runtime/Windows/D3D12RHI/Private/D3D12Query.cpp @@ -92,6 +92,7 @@ bool FD3D12Device::GetQueryData(FD3D12OcclusionQuery& Query, bool bWait) { // Wait for the query result to be ready (if requested). const FD3D12CLSyncPoint& SyncPoint = Query.CLSyncPoint; + if (!SyncPoint.IsComplete()) { if (!bWait) @@ -99,8 +100,25 @@ bool FD3D12Device::GetQueryData(FD3D12OcclusionQuery& Query, bool bWait) return false; } - check(!SyncPoint.IsOpen()); + SCOPE_CYCLE_COUNTER(STAT_RenderQueryResultTime); + uint32 IdleStart = FPlatformTime::Cycles(); + double StartTime = FPlatformTime::Seconds(); + + if (SyncPoint.IsOpen()) + { + // The query is on a command list that hasn't been submitted yet. + // We need to flush, but the RHI thread may be using the default command list...so stall it first. + check(IsInRenderingThread()); + check(Query.OwningContext->IsDefaultContext()); + + FScopedRHIThreadStaller StallRHIThread(FRHICommandListExecutor::GetImmediateCommandList()); + Query.OwningContext->FlushCommands(); // Don't wait yet, since we're stalling the RHI thread. + } + SyncPoint.WaitForCompletion(); + + GRenderThreadIdle[ERenderThreadIdleTypes::WaitingForGPUQuery] += FPlatformTime::Cycles() - IdleStart; + GRenderThreadNumIdle[ERenderThreadIdleTypes::WaitingForGPUQuery]++; } // Read the data from the query's buffer. diff --git a/Engine/Source/Runtime/Windows/D3D12RHI/Private/D3D12Query.h b/Engine/Source/Runtime/Windows/D3D12RHI/Private/D3D12Query.h index aa4758b2e018..934ed56d4255 100644 --- a/Engine/Source/Runtime/Windows/D3D12RHI/Private/D3D12Query.h +++ b/Engine/Source/Runtime/Windows/D3D12RHI/Private/D3D12Query.h @@ -26,6 +26,8 @@ public: // todo: memory optimize const ERenderQueryType Type; + class FD3D12CommandContext* OwningContext; + // When the query result is ready on the GPU. FD3D12CLSyncPoint CLSyncPoint; @@ -43,6 +45,7 @@ public: { HeapIndex = -1; bResultIsCached = false; + OwningContext = nullptr; } };