diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blitter.cs b/Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blitter.cs index 16bdb345dbf..c575831030a 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blitter.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blitter.cs @@ -69,7 +69,7 @@ public static void Initialize(Shader blitPS, Shader blitColorAndDepthPS) s_BlitTexArraySingleSlice.EnableKeyword("BLIT_SINGLE_SLICE"); } - if (SystemInfo.graphicsShaderLevel < 30) + if (SystemInfo.graphicsShaderLevel <= 30) { /*UNITY_NEAR_CLIP_VALUE*/ float nearClipZ = -1; @@ -186,7 +186,7 @@ static public Material GetBlitMaterial(TextureDimension dimension, bool singleSl static private void DrawTriangle(CommandBuffer cmd, Material material, int shaderPass) { - if (SystemInfo.graphicsShaderLevel < 30) + if (SystemInfo.graphicsShaderLevel <= 30) cmd.DrawMesh(s_TriangleMesh, Matrix4x4.identity, material, 0, shaderPass, s_PropertyBlock); else cmd.DrawProcedural(Matrix4x4.identity, material, shaderPass, MeshTopology.Triangles, 3, 1, s_PropertyBlock); @@ -194,7 +194,7 @@ static private void DrawTriangle(CommandBuffer cmd, Material material, int shade static internal void DrawQuad(CommandBuffer cmd, Material material, int shaderPass) { - if (SystemInfo.graphicsShaderLevel < 30) + if (SystemInfo.graphicsShaderLevel <= 30) cmd.DrawMesh(s_QuadMesh, Matrix4x4.identity, material, 0, shaderPass, s_PropertyBlock); else cmd.DrawProcedural(Matrix4x4.identity, material, shaderPass, MeshTopology.Quads, 4, 1, s_PropertyBlock); diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/CustomPass/CustomPassDrawer.cs b/Packages/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/CustomPass/CustomPassDrawer.cs index 0a10648e761..551a2507a7c 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/CustomPass/CustomPassDrawer.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/CustomPass/CustomPassDrawer.cs @@ -172,6 +172,16 @@ void DoCommonSettingsGUI(ref Rect rect) { EditorGUI.PropertyField(rect, m_TargetDepthBuffer, Styles.targetDepthBuffer); rect.y += Styles.defaultLineSpace; + + CustomPass.TargetBuffer requestedDepth = m_TargetDepthBuffer.GetEnumValue(); + if (m_CustomPass.getConstrainedDepthBuffer() != requestedDepth) + { + Rect helpBoxRect = rect; + float helpBoxHeight = EditorGUIUtility.singleLineHeight * 2; + helpBoxRect.height = helpBoxHeight; + EditorGUI.HelpBox(helpBoxRect, "Camera depth isn't supported when dynamic scaling is on. We will automatically fall back to not doing depth-testing for this pass.", MessageType.Warning); + rect.y += helpBoxHeight; + } } if ((commonPassUIFlags & PassUIFlag.ClearFlags) != 0) @@ -264,6 +274,13 @@ internal float GetPropertyHeight(SerializedProperty property, GUIContent label) } height += Styles.defaultLineSpace * lines; + + // Add height for the help box if it will be shown + if ((commonPassUIFlags & PassUIFlag.TargetDepthBuffer) != 0 && + m_CustomPass.getConstrainedDepthBuffer() != m_TargetDepthBuffer.GetEnumValue()) + { + height += EditorGUIUtility.singleLineHeight * 2; // Help box height + } } return height + GetPassHeight(property); diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoop.hlsl b/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoop.hlsl index 26065b3d383..9577d61a86d 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoop.hlsl +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoop.hlsl @@ -643,7 +643,7 @@ void LightLoop( float3 V, PositionInputs posInput, PreLightData preLightData, BS #if SHADEROPTIONS_AREA_LIGHTS if (featureFlags & LIGHTFEATUREFLAGS_AREA) { - uint lightCount, lightStart; + uint lightCount, lightStart; // Start is the offset specific to the tile (or cluster) #ifndef LIGHTLOOP_DISABLE_TILE_AND_CLUSTER GetCountAndStart(posInput, LIGHTCATEGORY_AREA, lightStart, lightCount); @@ -652,43 +652,57 @@ void LightLoop( float3 V, PositionInputs posInput, PreLightData preLightData, BS lightStart = _PunctualLightCount; #endif - // COMPILER BEHAVIOR WARNING! - // If rectangle lights are before line lights, the compiler will duplicate light matrices in VGPR because they are used differently between the two types of lights. - // By keeping line lights first we avoid this behavior and save substantial register pressure. - // TODO: This is based on the current Lit.shader and can be different for any other way of implementing area lights, how to be generic and ensure performance ? + bool fastPath = false; + #if SCALARIZE_LIGHT_LOOP + uint lightStartLane0; + fastPath = IsFastPath(lightStart, lightStartLane0); // True if all pixels belong to the same tile (or cluster) - if (lightCount > 0) + if (fastPath) { - i = 0; - - uint last = lightCount - 1; - LightData lightData = FetchLight(lightStart, i); + lightStart = lightStartLane0; + } + #endif - while (i <= last && lightData.lightType == GPULIGHTTYPE_TUBE) - { - lightData.lightType = GPULIGHTTYPE_TUBE; // Enforce constant propagation - lightData.cookieMode = COOKIEMODE_NONE; // Enforce constant propagation + // Scalarized loop. All lights that are in a tile/cluster touched by any pixel in the wave are loaded (scalar load), only the one relevant to current thread/pixel are processed. + // For clarity, the following code will follow the convention: variables starting with s_ are meant to be wave uniform (meant for scalar register), + // v_ are variables that might have different value for each thread in the wave (meant for vector registers). + // This will perform more loads than it is supposed to, however, the benefits should offset the downside, especially given that light data accessed should be largely coherent. + // Note that the above is valid only if wave intriniscs are supported. + uint v_lightListOffset = 0; + uint v_lightIdx = lightStart; - if (IsMatchingLightLayer(lightData.lightLayers, builtinData.renderingLayers)) - { - DirectLighting lighting = EvaluateBSDF_Area(context, V, posInput, preLightData, lightData, bsdfData, builtinData); - AccumulateDirectLighting(lighting, aggregateLighting); - } +#if NEED_TO_CHECK_HELPER_LANE + // On some platform helper lanes don't behave as we'd expect, therefore we prevent them from entering the loop altogether. + // IMPORTANT! This has implications if ddx/ddy is used on results derived from lighting, however given Lightloop is called in compute we should be + // sure it will not happen. + bool isHelperLane = WaveIsHelperLane(); + while (!isHelperLane && v_lightListOffset < lightCount) +#else + while (v_lightListOffset < lightCount) +#endif + { + v_lightIdx = FetchIndex(lightStart, v_lightListOffset); +#if SCALARIZE_LIGHT_LOOP + uint s_lightIdx = ScalarizeElementIndex(v_lightIdx, fastPath); +#else + uint s_lightIdx = v_lightIdx; +#endif + if (s_lightIdx == -1) + break; - lightData = FetchLight(lightStart, min(++i, last)); - } + LightData s_lightData = FetchLight(s_lightIdx); - while (i <= last) // GPULIGHTTYPE_RECTANGLE + // If current scalar and vector light index match, we process the light. The v_lightListOffset for current thread is increased. + // Note that the following should really be ==, however, since helper lanes are not considered by WaveActiveMin, such helper lanes could + // end up with a unique v_lightIdx value that is smaller than s_lightIdx hence being stuck in a loop. All the active lanes will not have this problem. + if (s_lightIdx >= v_lightIdx) { - lightData.lightType = GPULIGHTTYPE_RECTANGLE; // Enforce constant propagation - - if (IsMatchingLightLayer(lightData.lightLayers, builtinData.renderingLayers)) + v_lightListOffset++; + if (IsMatchingLightLayer(s_lightData.lightLayers, builtinData.renderingLayers)) { - DirectLighting lighting = EvaluateBSDF_Area(context, V, posInput, preLightData, lightData, bsdfData, builtinData); + DirectLighting lighting = EvaluateBSDF_Area(context, V, posInput, preLightData, s_lightData, bsdfData, builtinData); AccumulateDirectLighting(lighting, aggregateLighting); } - - lightData = FetchLight(lightStart, min(++i, last)); } } } diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/CustomPass/CustomPass.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/CustomPass/CustomPass.cs index 96014484f1f..22ae2012b00 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/CustomPass/CustomPass.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/CustomPass/CustomPass.cs @@ -52,6 +52,24 @@ internal ProfilingSampler profilingSampler /// public TargetBuffer targetDepthBuffer; + // The actual depth buffer has to follow some constraints, and thus may not be the same result as the target + // depth buffer that the user has requested. Apply these constraints and return a result. + internal TargetBuffer getConstrainedDepthBuffer() + { + TargetBuffer depth = targetDepthBuffer; + if (depth == TargetBuffer.Camera && + HDRenderPipeline.currentAsset.currentPlatformRenderPipelineSettings.dynamicResolutionSettings.enabled && + currentHDCamera.allowDynamicResolution && + injectionPoint == CustomPassInjectionPoint.AfterPostProcess) + { + // This custom pass is injected after postprocessing, and Dynamic Resolution Scaling is enabled, which + // means an upscaler is active. In this case, the camera color buffer is the full display resolution, + // but the camera depth buffer is a lower, pre-upscale resolution. So we cannot do depth testing here. + depth = TargetBuffer.None; + } + return depth; + } + /// /// What clear to apply when the color and depth buffer are bound /// @@ -272,7 +290,7 @@ virtual internal void ExecuteInternal(RenderGraph renderGraph, HDCamera hdCamera customPass.isExecuting = false; // Set back the camera color buffer if we were using a custom buffer as target - if (customPass.targetDepthBuffer != TargetBuffer.Camera) + if (customPass.getConstrainedDepthBuffer() != TargetBuffer.Camera) CoreUtils.SetRenderTarget(ctx.cmd, outputColorBuffer); }); } @@ -309,16 +327,17 @@ bool IsMSAAEnabled(HDCamera hdCamera) // This function must be only called from the ExecuteInternal method (requires current render target and current RT manager) void SetCustomPassTarget(CommandBuffer cmd) { + TargetBuffer depth = getConstrainedDepthBuffer(); // In case all the buffer are set to none, we can't bind anything - if (targetColorBuffer == TargetBuffer.None && targetDepthBuffer == TargetBuffer.None) + if (targetColorBuffer == TargetBuffer.None && depth == TargetBuffer.None) return; RTHandle colorBuffer = (targetColorBuffer == TargetBuffer.Custom) ? currentRenderTarget.customColorBuffer.Value : currentRenderTarget.colorBufferRG; - RTHandle depthBuffer = (targetDepthBuffer == TargetBuffer.Custom) ? currentRenderTarget.customDepthBuffer.Value : currentRenderTarget.depthBufferRG; + RTHandle depthBuffer = (depth == TargetBuffer.Custom) ? currentRenderTarget.customDepthBuffer.Value : currentRenderTarget.depthBufferRG; - if (targetColorBuffer == TargetBuffer.None && targetDepthBuffer != TargetBuffer.None) + if (targetColorBuffer == TargetBuffer.None && depth != TargetBuffer.None) CoreUtils.SetRenderTarget(cmd, depthBuffer, clearFlags); - else if (targetColorBuffer != TargetBuffer.None && targetDepthBuffer == TargetBuffer.None) + else if (targetColorBuffer != TargetBuffer.None && depth == TargetBuffer.None) CoreUtils.SetRenderTarget(cmd, colorBuffer, clearFlags); else { diff --git a/Packages/com.unity.render-pipelines.universal/Editor/2D/LightBatchingDebugger/LightBatchingDebugger.cs b/Packages/com.unity.render-pipelines.universal/Editor/2D/LightBatchingDebugger/LightBatchingDebugger.cs index f98c64c2e4a..660a9f08a15 100644 --- a/Packages/com.unity.render-pipelines.universal/Editor/2D/LightBatchingDebugger/LightBatchingDebugger.cs +++ b/Packages/com.unity.render-pipelines.universal/Editor/2D/LightBatchingDebugger/LightBatchingDebugger.cs @@ -162,7 +162,7 @@ private void ViewBatch(int index) foreach (var obj in batch1.Lights) { - if(obj != null) + if (obj != null) lightBubble1.Add(MakePill(obj)); } @@ -241,7 +241,7 @@ private void CompareBatch(int index1, int index2) lightBubble1.Clear(); foreach (var obj in lightSet1) { - if(obj != null) + if (obj != null) lightBubble1.Add(MakePill(obj)); } @@ -255,7 +255,7 @@ private void CompareBatch(int index1, int index2) lightBubble2.Clear(); foreach (var obj in lightSet2) { - if(obj != null) + if (obj != null) lightBubble2.Add(MakePill(obj)); } @@ -391,7 +391,7 @@ private void OnSelectionChanged() var firstIndex = batchListView.selectedIndices.First(); var secondIndex = batchListView.selectedIndices.Last(); - if(secondIndex > firstIndex + 1 || secondIndex < firstIndex - 1) + if (secondIndex > firstIndex + 1 || secondIndex < firstIndex - 1) { // Clamp since we do adjacent batch comparisons secondIndex = Mathf.Clamp(secondIndex, firstIndex - 1, firstIndex + 1); @@ -408,7 +408,7 @@ private void OnSelectionChanged() default: // Account for multiple select either with shift or ctrl keys - if(batchListView.selectedIndices.Count() > 2) + if (batchListView.selectedIndices.Count() > 2) { if (selectedIndices.Count == 1) { @@ -466,8 +466,12 @@ private bool IsDirty() isDirty |= Light2DManager.GetCachedSortingLayer().Count() != batchList.Sum(x => x.LayerNames.Count()); isDirty |= cachedSceneHandle != SceneManager.GetActiveScene().handle; isDirty |= cachedCamPos != Camera.main?.transform.position; - isDirty |= totalLightCount != lightCullResult.visibleLights.Count(); - isDirty |= totalShadowCount != lightCullResult.visibleShadows.Count(); + + if (lightCullResult.IsGameView()) + { + isDirty |= totalLightCount != lightCullResult.visibleLights.Count(); + isDirty |= totalShadowCount != lightCullResult.visibleShadows.Count(); + } return isDirty; } diff --git a/Packages/com.unity.render-pipelines.universal/Editor/2D/Renderer2DMenus.cs b/Packages/com.unity.render-pipelines.universal/Editor/2D/Renderer2DMenus.cs index f15f6c1f660..f7afb82e500 100644 --- a/Packages/com.unity.render-pipelines.universal/Editor/2D/Renderer2DMenus.cs +++ b/Packages/com.unity.render-pipelines.universal/Editor/2D/Renderer2DMenus.cs @@ -76,7 +76,8 @@ internal static void Place(GameObject go, GameObject parent) static Light2D CreateLight(MenuCommand menuCommand, Light2D.LightType type, Vector3[] shapePath = null) { - GameObject go = ObjectFactory.CreateGameObject("Light 2D", typeof(Light2D)); + var lightName = type != Light2D.LightType.Point ? type.ToString() : "Spot"; + GameObject go = ObjectFactory.CreateGameObject(lightName + " Light 2D", typeof(Light2D)); Light2D light2D = go.GetComponent(); light2D.lightType = type; diff --git a/Packages/com.unity.render-pipelines.universal/Shaders/Utils/ScreenSpaceShadows.shader b/Packages/com.unity.render-pipelines.universal/Shaders/Utils/ScreenSpaceShadows.shader index 9bf64a835ae..2b84a80d86f 100644 --- a/Packages/com.unity.render-pipelines.universal/Shaders/Utils/ScreenSpaceShadows.shader +++ b/Packages/com.unity.render-pipelines.universal/Shaders/Utils/ScreenSpaceShadows.shader @@ -20,10 +20,8 @@ Shader "Hidden/Universal Render Pipeline/ScreenSpaceShadows" { UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input); -#if UNITY_REVERSED_Z - float deviceDepth = SAMPLE_TEXTURE2D_X(_CameraDepthTexture, sampler_PointClamp, input.texcoord.xy).r; -#else - float deviceDepth = SAMPLE_TEXTURE2D_X(_CameraDepthTexture, sampler_PointClamp, input.texcoord.xy).r; + float deviceDepth = LoadSceneDepth(input.positionCS.xy); +#if !UNITY_REVERSED_Z deviceDepth = deviceDepth * 2.0 - 1.0; #endif diff --git a/Packages/com.unity.shadergraph/Editor/Data/Nodes/UV/ParallaxOcclusionMappingNode.cs b/Packages/com.unity.shadergraph/Editor/Data/Nodes/UV/ParallaxOcclusionMappingNode.cs index 4c5385e662e..d9a49c56168 100644 --- a/Packages/com.unity.shadergraph/Editor/Data/Nodes/UV/ParallaxOcclusionMappingNode.cs +++ b/Packages/com.unity.shadergraph/Editor/Data/Nodes/UV/ParallaxOcclusionMappingNode.cs @@ -10,7 +10,7 @@ namespace UnityEditor.ShaderGraph [Title("UV", "Parallax Occlusion Mapping")] [FormerName("UnityEditor.Experimental.Rendering.HDPipeline.ParallaxOcclusionMappingNode")] [FormerName("UnityEditor.Rendering.HighDefinition.ParallaxOcclusionMappingNode")] - class ParallaxOcclusionMappingNode : AbstractMaterialNode, IGeneratesBodyCode, IGeneratesFunction, IMayRequireViewDirection, IMayRequireMeshUV + class ParallaxOcclusionMappingNode : AbstractMaterialNode, IGeneratesBodyCode, IGeneratesFunction, IMayRequireViewDirection, IMayRequireMeshUV, IMayRequireTransform { public ParallaxOcclusionMappingNode() { @@ -220,6 +220,8 @@ public void GenerateNodeCode(ShaderStringBuilder sb, GenerationMode generationMo "); } + public NeededTransform[] RequiresTransform(ShaderStageCapability stageCapability = ShaderStageCapability.All) => new[] { NeededTransform.WorldToObject }; + public NeededCoordinateSpace RequiresViewDirection(ShaderStageCapability stageCapability = ShaderStageCapability.All) { return NeededCoordinateSpace.Tangent; diff --git a/Packages/com.unity.visualeffectgraph/Editor/Inspector/VFXAssetEditor.cs b/Packages/com.unity.visualeffectgraph/Editor/Inspector/VFXAssetEditor.cs index f8f7d308fdd..a80a6db939d 100644 --- a/Packages/com.unity.visualeffectgraph/Editor/Inspector/VFXAssetEditor.cs +++ b/Packages/com.unity.visualeffectgraph/Editor/Inspector/VFXAssetEditor.cs @@ -542,15 +542,16 @@ public static void DisplayPrewarmInspectorGUI(SerializedObject resourceObject, S if (!prewarmDeltaTime.hasMultipleDifferentValues && !prewarmStepCount.hasMultipleDifferentValues) { var currentDeltaTime = prewarmDeltaTime.floatValue; - var currentStepCount = prewarmStepCount.uintValue; + int currentStepCount = (int)prewarmStepCount.uintValue; var currentTotalTime = currentDeltaTime * currentStepCount; EditorGUI.BeginChangeCheck(); currentTotalTime = EditorGUILayout.FloatField(EditorGUIUtility.TrTextContent("PreWarm Total Time", "Sets the time in seconds to advance the current effect to when it is initially played. "), currentTotalTime); if (EditorGUI.EndChangeCheck()) { - if (currentStepCount <= 0) + if (currentStepCount <= 0 && currentTotalTime != 0.0f) { - prewarmStepCount.uintValue = currentStepCount = 1u; + currentStepCount = 1; + prewarmStepCount.uintValue = (uint)currentStepCount; } currentDeltaTime = currentTotalTime / currentStepCount; @@ -559,17 +560,18 @@ public static void DisplayPrewarmInspectorGUI(SerializedObject resourceObject, S } EditorGUI.BeginChangeCheck(); - currentStepCount = (uint)EditorGUILayout.IntField(EditorGUIUtility.TrTextContent("PreWarm Step Count", "Sets the number of simulation steps the prewarm should be broken down to. "), (int)currentStepCount); + currentStepCount = EditorGUILayout.IntField(EditorGUIUtility.TrTextContent("PreWarm Step Count", "Sets the number of simulation steps the prewarm should be broken down to. "), (int)currentStepCount); if (EditorGUI.EndChangeCheck()) { - if (currentStepCount <= 0 && currentTotalTime != 0.0f) + bool hasPrewarm = currentTotalTime != 0.0f; + if (currentStepCount <= 0) { - prewarmStepCount.uintValue = currentStepCount = 1; + currentStepCount = hasPrewarm ? 1 : 0; } - currentDeltaTime = currentTotalTime == 0.0f ? 0.0f : currentTotalTime / currentStepCount; + currentDeltaTime = hasPrewarm ? currentTotalTime / currentStepCount : 0.0f; prewarmDeltaTime.floatValue = currentDeltaTime; - prewarmStepCount.uintValue = currentStepCount; + prewarmStepCount.uintValue = (uint)currentStepCount; resourceObject.ApplyModifiedProperties(); } @@ -579,18 +581,18 @@ public static void DisplayPrewarmInspectorGUI(SerializedObject resourceObject, S { if (currentDeltaTime < k_MinimalCommonDeltaTime) { - prewarmDeltaTime.floatValue = currentDeltaTime = k_MinimalCommonDeltaTime; + currentDeltaTime = k_MinimalCommonDeltaTime; } - if (currentDeltaTime > currentTotalTime) + float totalTime = currentDeltaTime * currentStepCount; + if (totalTime > currentTotalTime) { - currentTotalTime = currentDeltaTime; + currentTotalTime = totalTime; } - - if (currentTotalTime != 0.0f) + else { - var candidateStepCount_A = (uint)Mathf.FloorToInt(currentTotalTime / currentDeltaTime); - var candidateStepCount_B = (uint)Mathf.RoundToInt(currentTotalTime / currentDeltaTime); + var candidateStepCount_A = Mathf.FloorToInt(currentTotalTime / currentDeltaTime); + var candidateStepCount_B = Mathf.RoundToInt(currentTotalTime / currentDeltaTime); var totalTime_A = currentDeltaTime * candidateStepCount_A; var totalTime_B = currentDeltaTime * candidateStepCount_B; @@ -604,7 +606,7 @@ public static void DisplayPrewarmInspectorGUI(SerializedObject resourceObject, S currentStepCount = candidateStepCount_B; } - prewarmStepCount.uintValue = currentStepCount; + prewarmStepCount.uintValue = (uint)currentStepCount; } prewarmDeltaTime.floatValue = currentDeltaTime; resourceObject.ApplyModifiedProperties();