diff --git a/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeGIBaking.cs b/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeGIBaking.cs index 245fb5c2..b126b6cf 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeGIBaking.cs +++ b/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeGIBaking.cs @@ -938,8 +938,11 @@ namespace UnityEngine.Rendering static bool InitializeBake() { - if (ProbeVolumeLightingTab.instance?.PrepareAPVBake() == false) return false; - if (!ProbeReferenceVolume.instance.isInitialized || !ProbeReferenceVolume.instance.enabledBySRP) return false; + if (ProbeVolumeLightingTab.instance?.PrepareAPVBake(ProbeReferenceVolume.instance) == false) + return false; + + if (!ProbeReferenceVolume.instance.isInitialized || !ProbeReferenceVolume.instance.enabledBySRP) + return false; using var scope = new BakingSetupProfiling(BakingSetupProfiling.Stages.PrepareWorldSubdivision); @@ -954,13 +957,16 @@ namespace UnityEngine.Rendering } } - if (ProbeReferenceVolume.instance.perSceneDataList.Count == 0) return false; + if (ProbeReferenceVolume.instance.perSceneDataList.Count == 0) + return false; var sceneDataList = GetPerSceneDataList(); - if (sceneDataList.Count == 0) return false; + if (sceneDataList.Count == 0) + return false; var pvList = GetProbeVolumeList(); - if (pvList.Count == 0) return false; // We have no probe volumes. + if (pvList.Count == 0) + return false; // We have no probe volumes. CachePVHashes(pvList); diff --git a/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeVolumeLightingTab.cs b/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeVolumeLightingTab.cs index fcd6253a..e0275f52 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeVolumeLightingTab.cs +++ b/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeVolumeLightingTab.cs @@ -102,7 +102,7 @@ namespace UnityEngine.Rendering } } - public static ProbeVolumeLightingTab instance; + public static ProbeVolumeLightingTab instance = new(); public static bool singleSceneMode => instance?.m_SingleSceneMode ?? true; @@ -957,9 +957,8 @@ namespace UnityEngine.Rendering return (bool)k_Lightmapping_BakeAllReflectionProbesSnapshots.Invoke(null, null); } - internal bool PrepareAPVBake() + internal bool PrepareAPVBake(ProbeReferenceVolume prv) { - var prv = ProbeReferenceVolume.instance; if (!prv.isInitialized || !prv.enabledBySRP) return false; @@ -979,9 +978,11 @@ namespace UnityEngine.Rendering { if(!activeSet.DialogNoProbeVolumeInSetShown()) { - if(EditorUtility.DisplayDialog("No Adaptive Probe Volume in Scene", "Adaptive Probe Volumes are enabled for this Project, but none exist in the Scene.\n\n" + - "Do you wish to add an Adaptive Probe Volume to the Active Scene?", "Yes", "No")) - CreateProbeVolume(); + if (!Application.isBatchMode) + if (EditorUtility.DisplayDialog("No Adaptive Probe Volume in Scene", + "Adaptive Probe Volumes are enabled for this Project, but none exist in the Scene.\n\n" + + "Do you wish to add an Adaptive Probe Volume to the Active Scene?", "Yes", "No")) + CreateProbeVolume(); activeSet.SetDialogNoProbeVolumeInSetShown(true); } } @@ -989,7 +990,13 @@ namespace UnityEngine.Rendering { if (GetFirstProbeVolumeInNonActiveScene() != null) { - int res = EditorUtility.DisplayDialogComplex("Create Baking Set?", "You are using the Single Scene Baking Mode and have more than one Scene loaded. It is not possible to generate lighting.\n\n" + + const string warning = "You are using the Single Scene Baking Mode and have more than one Scene loaded. It is not possible to generate lighting."; + if (Application.isBatchMode) + { + Debug.LogWarning(warning + " Consider creating a Baking Set."); + return false; + } + int res = EditorUtility.DisplayDialogComplex("Create Baking Set?", warning + "\n\n" + "Do you want to create a Baking Set instead?", "Yes", "Cancel", "Bake anyway"); if (res == 0) ConvertTempBakingSet(); @@ -1020,7 +1027,7 @@ namespace UnityEngine.Rendering if (AdaptiveProbeVolumes.partialBakeSceneList.Count == activeSet.sceneGUIDs.Count) AdaptiveProbeVolumes.partialBakeSceneList = null; - if (ProbeReferenceVolume.instance.supportLightingScenarios && !activeSet.m_LightingScenarios.Contains(activeSet.lightingScenario) && activeSet.m_LightingScenarios.Count > 0) + if (prv.supportLightingScenarios && !activeSet.m_LightingScenarios.Contains(activeSet.lightingScenario) && activeSet.m_LightingScenarios.Count > 0) activeSet.SetActiveScenario(activeSet.m_LightingScenarios[0], false); // Layout has changed and is incompatible. @@ -1028,14 +1035,26 @@ namespace UnityEngine.Rendering { if (AdaptiveProbeVolumes.partialBakeSceneList != null) { - if (EditorUtility.DisplayDialog("Incompatible Layout", "You are partially baking the set with an incompatible cell layout. Proceeding will invalidate all previously bake data.\n\n" + "Do you wish to continue?", "Yes", "No")) + const string warning = "You are partially baking the set with an incompatible cell layout."; + if (Application.isBatchMode) + { + Debug.LogWarning(warning); + return false; + } + if (EditorUtility.DisplayDialog("Incompatible Layout", warning + " Proceeding will invalidate all previously bake data.\n\n" + "Do you wish to continue?", "Yes", "No")) ClearBakedData(); else return false; } - else if (ProbeReferenceVolume.instance.supportLightingScenarios && activeSet.scenarios.Count != (activeSet.scenarios.ContainsKey(activeSet.lightingScenario) ? 1 : 0)) + else if (prv.supportLightingScenarios && activeSet.scenarios.Count != (activeSet.scenarios.ContainsKey(activeSet.lightingScenario) ? 1 : 0)) { - if (EditorUtility.DisplayDialog("Incompatible Layout", "You are baking scenarios with incompatible cell layouts. Proceeding will invalidate all previously bake data.\n\n" + "Do you wish to continue?", "Yes", "No")) + const string warning = "You are baking scenarios with incompatible cell layouts."; + if (Application.isBatchMode) + { + Debug.LogWarning(warning); + return false; + } + if (EditorUtility.DisplayDialog("Incompatible Layout", warning + " Proceeding will invalidate all previously bake data.\n\n" + "Do you wish to continue?", "Yes", "No")) ClearBakedData(); else return false; diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugDisplaySettingsVolumes.cs b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugDisplaySettingsVolumes.cs index f7f88572..76c6dc06 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugDisplaySettingsVolumes.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugDisplaySettingsVolumes.cs @@ -478,15 +478,11 @@ namespace UnityEngine.Rendering for (int i = 0; i < results.parameterList.Count; ++i) { var parameter = results.parameterList[i]; - -#if UNITY_EDITOR - string displayName = UnityEditor.ObjectNames.NicifyVariableName(parameter.debugId); // In the editor, make the name more readable -#elif DEVELOPMENT_BUILD - string displayName = parameter.debugId; // In the development player, just the debug id +#if UNITY_EDITOR || DEVELOPMENT_BUILD + string displayName = VolumeDebugData.GetVolumeParameterDebugId(parameter);// In the development player, just the debug id #else string displayName = i.ToString(); // Everywhere else, just a dummy id ( TODO: The Volume panel code should be stripped completely in nom-development builds ) #endif - table.children.Add(new DebugUI.Table.Row() { displayName = displayName diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolumesOptions.cs b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolumesOptions.cs index 4148af54..2e3518ff 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolumesOptions.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolumesOptions.cs @@ -22,6 +22,7 @@ namespace UnityEngine.Rendering /// A volume component that holds settings for the Adaptive Probe Volumes System per-camera options. /// [Serializable, VolumeComponentMenu("Lighting/Adaptive Probe Volumes Options"), SupportedOnRenderPipeline] + [CurrentPipelineHelpURL("probevolumes")] public sealed class ProbeVolumesOptions : VolumeComponent { ProbeVolumesOptions() diff --git a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Compiler/PassesData.cs b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Compiler/PassesData.cs index 2b303faf..4a65850f 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Compiler/PassesData.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Compiler/PassesData.cs @@ -1115,89 +1115,63 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler passToMerge.nativeSubPassIndex = nativePass.numNativeSubPasses - 1; } - // In the case where we add a new graph pass with depth to a native pass that didn't have it, we need to update - // inputs in all the previous native subpasses of the native pass - static void UpdateNativeSubPassesAttachments(CompilerContextData contextData, ref NativePassData nativePass) + // Call this function while merging a graph pass and you need to add the depth attachment used by this graph pass + // Make sure to call it before adding the rest of the graph pass attachments and its generated subpass + void AddDepthAttachmentFirstDuringMerge(CompilerContextData contextData, in PassFragmentData depthAttachment) { - int lastVisitedNativeSubpassIdx = -1; - ref readonly var fragmentList = ref nativePass.fragments; + // Native pass can only have a single depth attachment + Debug.Assert(!hasDepth); - var countPasses = nativePass.lastGraphPass - nativePass.firstGraphPass + 1; + fragments.Add(depthAttachment); + hasDepth = true; - // Do not iterate over the last graph pass as it is the one we are currently adding - for (var graphPassIdx = 0; graphPassIdx < countPasses - 1; ++graphPassIdx) - { - // We only check the first graph pass of each existing native subpass - if other graph passes - // have been merged into a native subpass, it's because they had the same attachments. - ref readonly var currGraphPass = - ref contextData.passData.ElementAt(nativePass.firstGraphPass + graphPassIdx); + var size = fragments.size; - // Already updated this native subpass - if (currGraphPass.nativeSubPassIndex + nativePass.firstNativeSubPass == lastVisitedNativeSubpassIdx) - { - continue; - } + // If depth is the only attachment of the native pass, we are done + if (size == 1) return; - // Shouldn't be necessary since we only check the first graph pass of each existing native subpass - // But let's be safe and check anyway if the pass has been culled or not. - if (currGraphPass.culled) - { - continue; - } + // size > 1 + // In this case, we are adding depth attachment to a native pass with other existing attachments + int prevDepthIdx = size - 1; - lastVisitedNativeSubpassIdx = currGraphPass.nativeSubPassIndex + nativePass.firstNativeSubPass; - ref var nativeSubPassDescriptor = - ref contextData.nativeSubPassData.ElementAt(lastVisitedNativeSubpassIdx); + // Depth must always been the first attachment, so we switch the previous first one with the recently added depth attachment + (fragments[0], fragments[prevDepthIdx]) = (fragments[prevDepthIdx], fragments[0]); + + var depthFlag = GetSubPassFlagForMerging(); + + // We also need to increment the attachment indices of all the previous subpasses of this native pass. + // Otherwise the existing subpasses will point to the wrong attachments with depth being set as the first one + for (var nativeSubPassIndex = firstNativeSubPass; nativeSubPassIndex < firstNativeSubPass + numNativeSubPasses; nativeSubPassIndex++) + { + ref var subPassDesc = ref contextData.nativeSubPassData.ElementAt(nativeSubPassIndex); // If depth ends up being bound only because of merging - if (!currGraphPass.fragmentInfoHasDepth && nativePass.hasDepth) + // Set SubPassFlags to best match the pass we are trying to merge with + subPassDesc.flags = depthFlag; + + // Updating subpass color outputs + for (int i = 0; i < subPassDesc.colorOutputs.Length; i++) { - // Set SubPassFlags to best match the pass we are trying to merge with - nativeSubPassDescriptor.flags = nativePass.GetSubPassFlagForMerging(); + if (subPassDesc.colorOutputs[i] == 0) + { + subPassDesc.colorOutputs[i] = prevDepthIdx; + } } - // MRT attachments + // Updating subpass color inputs (framebuffer fetch) + for (int i = 0; i < subPassDesc.inputs.Length; i++) { - int fragmentIdx = 0; - int colorOffset = (currGraphPass.fragmentInfoHasDepth) ? -1 : 0; - - nativeSubPassDescriptor.colorOutputs = - new AttachmentIndexArray(currGraphPass.numFragments + colorOffset); - - foreach (ref readonly var graphPassFragment in currGraphPass.Fragments(contextData)) + if (subPassDesc.inputs[i] == 0) { - // Check if we're handling the depth attachment - if (currGraphPass.fragmentInfoHasDepth && fragmentIdx == 0) - { - nativeSubPassDescriptor.flags = (graphPassFragment.accessFlags.HasFlag(AccessFlags.Write)) - ? SubPassFlags.None - : SubPassFlags.ReadOnlyDepth; - } - // It's a color attachment - else - { - // Find the index of this subpass's attachment in the native renderpass attachment list - int colorAttachmentIdx = -1; - for (int fragmentId = 0; fragmentId < fragmentList.size; ++fragmentId) - { - if (fragmentList[fragmentId].resource.index == graphPassFragment.resource.index) - { - colorAttachmentIdx = fragmentId; - break; - } - } - - Debug.Assert(colorAttachmentIdx >= - 0); // If this is not the case it means we are using an attachment in a sub pass that is not part of the native pass !?!? clear bug - - // Set up the color indexes - nativeSubPassDescriptor.colorOutputs[fragmentIdx + colorOffset] = colorAttachmentIdx; - } - - fragmentIdx++; + subPassDesc.inputs[i] = prevDepthIdx; } } + } + // We also need to update the shading rate image index (VRS) + if (hasShadingRateImage && shadingRateImageIndex == 0) + { + shadingRateImageIndex = prevDepthIdx; } } @@ -1224,14 +1198,7 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler // as we require the depth attachment to be at index 0 if (!nativePass.hasDepth && passToMerge.fragmentInfoHasDepth) { - nativePass.hasDepth = true; - nativePass.fragments.Add(contextData.fragmentData[passToMerge.firstFragment]); - var size = nativePass.fragments.size; - if (size > 1) - (nativePass.fragments[0], nativePass.fragments[size-1]) = (nativePass.fragments[size-1], nativePass.fragments[0]); - - // Must update indices from Native subPasses created before - UpdateNativeSubPassesAttachments(contextData, ref nativePass); + nativePass.AddDepthAttachmentFirstDuringMerge(contextData, contextData.fragmentData[passToMerge.firstFragment]); } // Update versions and flags of existing attachments and diff --git a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphUtilsBlit.cs b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphUtilsBlit.cs index a0600bd5..922466b7 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphUtilsBlit.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphUtilsBlit.cs @@ -20,6 +20,16 @@ namespace UnityEngine.Rendering.RenderGraphModule.Util return Blitter.CanCopyMSAA(); } + /// + /// Checks if the shader features required by the MSAA version of the copy pass is supported on current platform. + /// + /// The texture description of the that will be copied from. + /// Returns true if the shader features required by the copy pass is supported for MSAA, otherwise will it return false. + public static bool CanAddCopyPassMSAA(in TextureDesc sourceDesc) + { + return Blitter.CanCopyMSAA(sourceDesc); + } + class CopyPassData { public bool isMSAA; @@ -80,7 +90,7 @@ namespace UnityEngine.Rendering.RenderGraphModule.Util // It would have 1 if the MSAA pass is not able to be used for target and 2 otherwise. // https://docs.unity3d.com/2017.4/Documentation/Manual/SL-ShaderCompileTargets.html // https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-to-get-sample-position - if (isMSAA && !Blitter.CanCopyMSAA()) + if (isMSAA && !Blitter.CanCopyMSAA(sourceDesc)) throw new ArgumentException("Target does not support MSAA for AddCopyPass. Please use the blit alternative or use non MSAA textures."); using (var builder = graph.AddRasterRenderPass(passName, out var passData, file, line)) 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 dfd48165..56644868 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blitter.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blitter.cs @@ -5,6 +5,7 @@ using UnityEngine.Assertions; using System.Text.RegularExpressions; using UnityEngine.Rendering.RenderGraphModule.Util; using UnityEngine.Rendering.RenderGraphModule; + #if UNITY_EDITOR using UnityEditor; #endif @@ -341,10 +342,9 @@ namespace UnityEngine.Rendering internal static bool CanCopyMSAA() { - //Temporary disable most msaa copies as we fix UUM-67324 which is a bit more involved due to the internal work required - GraphicsDeviceType deviceType = SystemInfo.graphicsDeviceType; - if (deviceType != GraphicsDeviceType.Metal || deviceType != GraphicsDeviceType.Vulkan) + if (SystemInfo.graphicsDeviceType == GraphicsDeviceType.PlayStation4) { + // Will be done later, see: UUM-97281 return false; } @@ -354,10 +354,34 @@ namespace UnityEngine.Rendering return s_Copy.passCount == 2; } + internal static bool CanCopyMSAA(in TextureDesc sourceDesc) + { + + // Real native renderpass platforms + // TODO: Expose this through systeminfo + bool hasRenderPass = + SystemInfo.graphicsDeviceType == GraphicsDeviceType.Metal + || SystemInfo.graphicsDeviceType == GraphicsDeviceType.Vulkan + || SystemInfo.graphicsDeviceType == GraphicsDeviceType.Direct3D12; + + if (SystemInfo.supportsMultisampleAutoResolve && + !hasRenderPass && sourceDesc.bindTextureMS == false) + { + // If we have autoresolve it means msaa rendertextures render as MSAA but magically resolve in the driver when accessed as a texture, the MSAA surface is fully hidden inside the GFX device + // this is contrary to most platforms where the resolve magic on reading happens in the engine layer (and thus allocates proper multi sampled and resolve surfaces the engine can access) + // So in the cases of auto resolving, and a renderpass framebuffer fetch emulation layer we can't correctly access the individual unresolved msaa samples and thus don't allow this case here + // Note: In practice the above check mostly triggers on GLES. + return false; + } + + return CanCopyMSAA(); + } + /// /// Copies a texture to another texture using framebuffer fetch. /// /// Command Buffer used for rendering. + /// Use the MSAA variant of the copy shader (otherwise single sample is used). /// Disable the special handling when XR is active where the source and destination are considered array /// textures with a slice for each eye. Setting this to true will consider source and destination as regular 2D textures. When XR is /// disabled, textures are always 2D so forcing them to 2D has no impact. diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Volume/VolumeComponent.cs b/Packages/com.unity.render-pipelines.core/Runtime/Volume/VolumeComponent.cs index 17fb6b19..3f2bf8b9 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Volume/VolumeComponent.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Volume/VolumeComponent.cs @@ -201,15 +201,7 @@ namespace UnityEngine.Rendering { VolumeParameter volumeParameter = (VolumeParameter)field.GetValue(o); #if UNITY_EDITOR || DEVELOPMENT_BUILD - var attr = (DisplayInfoAttribute[])field.GetCustomAttributes(typeof(DisplayInfoAttribute), true); - if (attr.Length != 0) - { - volumeParameter.debugId = attr[0].name; - } - else - { - volumeParameter.debugId = field.Name; - } + VolumeDebugData.AddVolumeParameterDebugId(volumeParameter, field); #endif parameters.Add(volumeParameter); } diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Volume/VolumeDebugData.cs b/Packages/com.unity.render-pipelines.core/Runtime/Volume/VolumeDebugData.cs new file mode 100644 index 00000000..7dad87b0 --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Runtime/Volume/VolumeDebugData.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Reflection; + +namespace UnityEngine.Rendering +{ +#if UNITY_EDITOR || DEVELOPMENT_BUILD + internal static class VolumeDebugData + { + static Lazy> debugIds = new(() => new Dictionary()); + + internal static string GetVolumeParameterDebugId(VolumeParameter parameter) + { + return debugIds.Value.TryGetValue(parameter.fieldHash, out var debugId) ? debugId : string.Empty; + } + + internal static void AddVolumeParameterDebugId(VolumeParameter parameter, FieldInfo field) + { + var fieldHash = field.GetHashCode(); + parameter.fieldHash = fieldHash; + if (debugIds.Value.ContainsKey(fieldHash)) + return; + + var displayInfo = field.GetCustomAttribute(true); + var debugId = displayInfo != null ? displayInfo.name : field.Name; +#if UNITY_EDITOR + debugId = UnityEditor.ObjectNames.NicifyVariableName(debugId); // In the editor, make the name more readable +#endif + debugIds.Value.Add(fieldHash, debugId); + } + } +#endif +} \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Volume/VolumeDebugData.cs.meta b/Packages/com.unity.render-pipelines.core/Runtime/Volume/VolumeDebugData.cs.meta new file mode 100644 index 00000000..f3d5f4cf --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Runtime/Volume/VolumeDebugData.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a359de1dc98b4f1db3fffb9601eb785b +timeCreated: 1743511791 \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Volume/VolumeParameter.cs b/Packages/com.unity.render-pipelines.core/Runtime/Volume/VolumeParameter.cs index 723f21e4..7c44195f 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Volume/VolumeParameter.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Volume/VolumeParameter.cs @@ -30,7 +30,7 @@ namespace UnityEngine.Rendering public abstract class VolumeParameter : ICloneable { #if UNITY_EDITOR || DEVELOPMENT_BUILD - internal string debugId { get; set; } + internal int fieldHash { get; set; } #endif /// diff --git a/Packages/com.unity.render-pipelines.core/Tests/Editor/NativePassCompilerRenderGraphTests.cs b/Packages/com.unity.render-pipelines.core/Tests/Editor/NativePassCompilerRenderGraphTests.cs index 7dc8ad23..0aee4175 100644 --- a/Packages/com.unity.render-pipelines.core/Tests/Editor/NativePassCompilerRenderGraphTests.cs +++ b/Packages/com.unity.render-pipelines.core/Tests/Editor/NativePassCompilerRenderGraphTests.cs @@ -1416,5 +1416,167 @@ namespace UnityEngine.Rendering.Tests return gcAllocRecorder.sampleBlockCount; } } + + [Test] + public void UpdateSubpassAttachmentIndices_WhenDepthAttachmentIsAdded() + { + var g = AllocateRenderGraph(); + var buffers = ImportAndCreateBuffers(g); + + using (var builder = g.AddRasterRenderPass("NoDepth0_Subpass0", out var passData)) + { + builder.SetRenderAttachment(buffers.extraBuffers[0], 0); + builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { }); + builder.AllowPassCulling(false); + } + + // Render Pass + // attachments: [extraBuffers[0]] + // subpass 0: color outputs : [0] + + using (var builder = g.AddRasterRenderPass("NoDepth1_Subpass0", out var passData)) + { + builder.SetRenderAttachment(buffers.extraBuffers[0], 0); + builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { }); + builder.AllowPassCulling(false); + } + + // Render Pass + // attachments: [extraBuffers[0]] + // subpass 0: color outputs : [0] + + using (var builder = g.AddRasterRenderPass("NoDepth2_Subpass1", out var passData)) + { + builder.SetRenderAttachment(buffers.extraBuffers[1], 0); + builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { }); + builder.AllowPassCulling(false); + } + + // Render Pass + // attachments: [extraBuffers[0], extraBuffers[1]] + // subpass 0: color outputs : [0] + // subpass 1: color outputs : [1] + + using (var builder = g.AddRasterRenderPass("NoDepth3_Subpass2", out var passData)) + { + builder.SetInputAttachment(buffers.extraBuffers[0], 0); + builder.SetInputAttachment(buffers.extraBuffers[1], 1); + builder.SetRenderAttachment(buffers.extraBuffers[2], 0); + builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { }); + builder.AllowPassCulling(false); + } + + // Render Pass + // attachments: [extraBuffers[0], extraBuffers[1], extraBuffers[2]] + // subpass 0: color outputs : [0] + // subpass 1: color outputs : [1] + // subpass 2: color outputs : [2], inputs : [0, 1] + + using (var builder = g.AddRasterRenderPass("Depth_Subpass3", out var passData)) + { + builder.SetInputAttachment(buffers.extraBuffers[0], 0); + builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write); + builder.SetRenderAttachment(buffers.extraBuffers[3], 0); + builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { }); + builder.AllowPassCulling(false); + } + + // Render Pass + // attachments: [depthBuffer, extraBuffers[1], extraBuffers[2], extraBuffers[0], extraBuffers[3]] + // subpass 0: color outputs : [0 -> 3] + // subpass 1: color outputs : [1] + // subpass 2: color outputs : [2], inputs : [0 -> 3, 1] + // subpass 3: color outputs : [4], inputs : [3] + + var result = g.CompileNativeRenderGraph(g.ComputeGraphHash()); + var passes = result.contextData.GetNativePasses(); + + // All graph passes are merged in the same render pass + Assert.IsTrue(passes != null && passes.Count == 1 && passes[0].numGraphPasses == 5 && passes[0].numNativeSubPasses == 4); + + // Depth is the first attachment + Assert.IsTrue(passes[0].attachments[0].handle.index == buffers.depthBuffer.handle.index); + Assert.IsTrue(passes[0].attachments[1].handle.index == buffers.extraBuffers[1].handle.index); + Assert.IsTrue(passes[0].attachments[2].handle.index == buffers.extraBuffers[2].handle.index); + Assert.IsTrue(passes[0].attachments[3].handle.index == buffers.extraBuffers[0].handle.index); + Assert.IsTrue(passes[0].attachments[4].handle.index == buffers.extraBuffers[3].handle.index); + + // Check first subpass is correctly updated + ref var subPassDesc0 = ref result.contextData.nativeSubPassData.ElementAt(0); + Assert.IsTrue(subPassDesc0.colorOutputs.Length == 1); + Assert.IsTrue(subPassDesc0.colorOutputs[0] == 3); + + // Check second subpass is correctly updated + ref var subPassDesc1 = ref result.contextData.nativeSubPassData.ElementAt(1); + Assert.IsTrue(subPassDesc1.colorOutputs.Length == 1); + Assert.IsTrue(subPassDesc1.colorOutputs[0] == 1); + + // Check third subpass is correctly updated + ref var subPassDesc2 = ref result.contextData.nativeSubPassData.ElementAt(2); + Assert.IsTrue(subPassDesc2.colorOutputs.Length == 1); + Assert.IsTrue(subPassDesc2.colorOutputs[0] == 2); + Assert.IsTrue(subPassDesc2.inputs.Length == 2); + Assert.IsTrue(subPassDesc2.inputs[0] == 3); + Assert.IsTrue(subPassDesc2.inputs[1] == 1); + + // Check fourth subpass with depth is correct + ref var subPassDesc3 = ref result.contextData.nativeSubPassData.ElementAt(3); + Assert.IsTrue(subPassDesc3.colorOutputs.Length == 1); + Assert.IsTrue(subPassDesc3.colorOutputs[0] == 4); + Assert.IsTrue(subPassDesc3.inputs.Length == 1); + Assert.IsTrue(subPassDesc3.inputs[0] == 3); + } + +/* //VRS bug. It seems that there is a bug with VRS forcing pass breaking between passes using the same shading rate image where it shouldn't: UUM-102113. + [Test] + public void UpdateShadingRateImageIndex_WhenDepthAttachmentIsAdded() + { + var g = AllocateRenderGraph(); + var buffers = ImportAndCreateBuffers(g); + + using (var builder = g.AddRasterRenderPass("NoDepth_Subpass0", out var passData)) + { + builder.SetShadingRateImageAttachment(buffers.extraBuffers[0]); + builder.SetRenderAttachment(buffers.extraBuffers[1], 0); + builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { }); + builder.AllowPassCulling(false); + } + + // Render Pass + // attachments: [extraBuffers[0], extraBuffers[1]] + // shading rate image : [0] + // subpass 0: color outputs : [1] + + using (var builder = g.AddRasterRenderPass("Depth_Subpass1", out var passData)) + { + builder.SetShadingRateImageAttachment(buffers.extraBuffers[0]); + builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write); + builder.SetRenderAttachment(buffers.extraBuffers[2], 0); + builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { }); + builder.AllowPassCulling(false); + } + + // Render Pass + // attachments: [depthBuffer, extraBuffers[1], extraBuffers[0], extraBuffers[2]] + // shading rate image : [0 -> 2] + // subpass 0: color outputs : [1] + // subpass 1: color outputs : [3] + + var result = g.CompileNativeRenderGraph(g.ComputeGraphHash()); + var passes = result.contextData.GetNativePasses(); + + // All graph passes are merged in the same render pass + Assert.IsTrue(passes != null && passes.Count == 1 && passes[0].numGraphPasses == 2 && passes[0].numNativeSubPasses == 2); + + // Depth is the first attachment + Assert.IsTrue(passes[0].attachments[0].handle.index == buffers.depthBuffer.handle.index); + Assert.IsTrue(passes[0].attachments[1].handle.index == buffers.extraBuffers[1].handle.index); + Assert.IsTrue(passes[0].attachments[2].handle.index == buffers.extraBuffers[0].handle.index); + Assert.IsTrue(passes[0].attachments[3].handle.index == buffers.extraBuffers[2].handle.index); + + // Check Shading Rate Image index is correctly updated + Assert.IsTrue(passes[0].shadingRateImageIndex == buffers.extraBuffers[0].handle.index); + } +*/ } } diff --git a/Packages/com.unity.render-pipelines.core/Tests/Runtime/RuntimeProfilerTests.cs b/Packages/com.unity.render-pipelines.core/Tests/Runtime/RuntimeProfilerTests.cs index 4a0468a9..1543e270 100644 --- a/Packages/com.unity.render-pipelines.core/Tests/Runtime/RuntimeProfilerTests.cs +++ b/Packages/com.unity.render-pipelines.core/Tests/Runtime/RuntimeProfilerTests.cs @@ -55,10 +55,11 @@ namespace UnityEngine.Rendering.Tests } } - // Fails on WebGL and Oculus Quest. + // Fails on WebGL, Oculus Quest and Embedded Platforms (GLES3). // Unfortunately, there is no good way to exclude Oculus Quest from the test without excluding all Android devices. // https://jira.unity3d.com/browse/GFXFOUND-559 - [UnityPlatform(exclude = new RuntimePlatform[] { RuntimePlatform.WebGLPlayer, RuntimePlatform.Android })] + // https://jira.unity3d.com/browse/PLAT-13842 (GLES3 gpuFrameTime is currently only available on Android) + [UnityPlatform(exclude = new RuntimePlatform[] { RuntimePlatform.WebGLPlayer, RuntimePlatform.Android, RuntimePlatform.EmbeddedLinuxArm64 })] class RuntimeProfilerTests : RuntimeProfilerTestBase { [UnityTest] diff --git a/Packages/com.unity.render-pipelines.core/package.json b/Packages/com.unity.render-pipelines.core/package.json index 08e08c87..1df56e30 100644 --- a/Packages/com.unity.render-pipelines.core/package.json +++ b/Packages/com.unity.render-pipelines.core/package.json @@ -14,5 +14,5 @@ "com.unity.modules.jsonserialize": "1.0.0", "com.unity.rendering.light-transport": "1.0.1" }, - "_fingerprint": "e1ccf0da7b7866fa5b58ea14860297de7848dfd2" + "_fingerprint": "79d3abb9adf1668400072f165c52ac7c03b1bca9" } diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/PropertyDrawers/LookDevVolumeProfileSettingsPropertyDrawer.cs b/Packages/com.unity.render-pipelines.high-definition/Editor/PropertyDrawers/LookDevVolumeProfileSettingsPropertyDrawer.cs index cd0e7f96..99cc74a5 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Editor/PropertyDrawers/LookDevVolumeProfileSettingsPropertyDrawer.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/PropertyDrawers/LookDevVolumeProfileSettingsPropertyDrawer.cs @@ -111,7 +111,7 @@ namespace UnityEditor.Rendering.HighDefinition if (lookDevVolumeProfileSettings.volumeProfile == null) { lookDevVolumeProfileSettings.volumeProfile = VolumeUtils.CopyVolumeProfileFromResourcesToAssets( - GraphicsSettings.GetRenderPipelineSettings().defaultVolumeProfile); + GraphicsSettings.GetRenderPipelineSettings().lookDevVolumeProfile); } m_VolumeProfileSerializedProperty.objectReferenceValue = lookDevVolumeProfileSettings.volumeProfile; diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/GlobalIllumination.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/GlobalIllumination.cs index 85d2e17a..9b1e4493 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/GlobalIllumination.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/GlobalIllumination.cs @@ -8,7 +8,7 @@ namespace UnityEngine.Rendering.HighDefinition /// [Serializable, VolumeComponentMenu("Lighting/Screen Space Global Illumination")] [SupportedOnRenderPipeline(typeof(HDRenderPipelineAsset))] - [HDRPHelpURL("Ray-Traced-Global-Illumination")] + [HDRPHelpURL("Override-Screen-Space-GI")] public sealed class GlobalIllumination : VolumeComponentWithQuality { bool UsesQualityMode() diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.RenderGraph.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.RenderGraph.cs index 77ec146e..0807c021 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.RenderGraph.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.RenderGraph.cs @@ -1571,7 +1571,8 @@ namespace UnityEngine.Rendering.HighDefinition if (!output.enablePerPixelSorting) return output; - output.depthBufferPreRefraction = CreateDepthBuffer(renderGraph, false, hdCamera.msaaSamples, "CameraDepthStencil PreRefraction", false); + output.depthBufferPreRefraction = CreateDepthBuffer(renderGraph, m_HasResolutionChanged, hdCamera.msaaSamples, "CameraDepthStencil PreRefraction", false); + m_HasResolutionChanged = false; output.beforeRefraction = renderGraph.CreateTexture(new TextureDesc(Vector2.one, true, true) { format = GraphicsFormat.B10G11R11_UFloatPack32, msaaSamples = hdCamera.msaaSamples, clearBuffer = true, name = "Before Refraction" }); diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs index 9968c8e4..c8950b8f 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs @@ -211,6 +211,9 @@ namespace UnityEngine.Rendering.HighDefinition // User render requests can use different ones to avoid mixing history information HDCamera.HistoryChannel m_CurrentCameraHistoryChannel = HDCamera.HistoryChannel.RenderLoopHistory; + bool m_HasResolutionChanged = false; + Action m_OnResolutionChanged; + internal GraphicsFormat GetColorBufferFormat() { if (CoreUtils.IsSceneFilteringEnabled()) @@ -723,6 +726,11 @@ namespace UnityEngine.Rendering.HighDefinition #if UNITY_EDITOR GPUInlineDebugDrawer.Initialize(); #endif + + m_OnResolutionChanged = () => + { + m_HasResolutionChanged = true; + }; } private void SetLodQualitySettings() @@ -1066,6 +1074,7 @@ namespace UnityEngine.Rendering.HighDefinition #if UNITY_EDITOR GPUInlineDebugDrawer.Dispose(); #endif + m_OnResolutionChanged = null; } void Resize(HDCamera hdCamera) @@ -2280,7 +2289,7 @@ namespace UnityEngine.Rendering.HighDefinition // only select the current instance for this camera. We dont pass the settings set to prevent an update. // This will set a new instance in DynamicResolutionHandler.instance that is specific to this camera. - DynamicResolutionHandler.UpdateAndUseCamera(camera); + DynamicResolutionHandler.UpdateAndUseCamera(camera, null, m_OnResolutionChanged); //Warning!! do not read anything off the dynResHandler, until we have called Update(). Otherwise, the handler is in the process of getting constructed. var dynResHandler = DynamicResolutionHandler.instance; diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Settings/LookDevVolumeProfileSettings.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/Settings/LookDevVolumeProfileSettings.cs index cd3226f8..99691e07 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Settings/LookDevVolumeProfileSettings.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Settings/LookDevVolumeProfileSettings.cs @@ -69,7 +69,13 @@ namespace UnityEngine.Rendering.HighDefinition #if UNITY_EDITOR if (UnityEditor.Rendering.EditorGraphicsSettings.TryGetRenderPipelineSettingsForPipeline(out var rpgs)) { - volumeProfile = VolumeUtils.CopyVolumeProfileFromResourcesToAssets(rpgs.lookDevVolumeProfile); + //UUM-100350 + //When opening the new HDRP project from the template the first time, the global settings is created and the population of IRenderPipelineGraphicsSettings + //will call this Reset() method. At this time, the copied item will appear ok but will be seen as null soon after. This lead to errors when opening the + //inspector of the LookDev's VolumeProfile (at the creation of Editors for VolumeComponent). Closing and opening the project would make this issue disappear. + //This asset data base manipulation issue disappear if we delay it. + UnityEditor.EditorApplication.delayCall += () => + volumeProfile = VolumeUtils.CopyVolumeProfileFromResourcesToAssets(rpgs.lookDevVolumeProfile); } #endif } diff --git a/Packages/com.unity.render-pipelines.high-definition/package.json b/Packages/com.unity.render-pipelines.high-definition/package.json index 81e5a434..d611f7ac 100644 --- a/Packages/com.unity.render-pipelines.high-definition/package.json +++ b/Packages/com.unity.render-pipelines.high-definition/package.json @@ -100,5 +100,5 @@ ] } ], - "_fingerprint": "d227fa58be29c449fb909ae51545deea1ba1a475" + "_fingerprint": "4de1dfa20daa1dde4106c2c4990e5356c4cbf1e7" } diff --git a/Packages/com.unity.shadergraph/Editor/Generation/Processors/Generator.cs b/Packages/com.unity.shadergraph/Editor/Generation/Processors/Generator.cs index 926f78ca..76787bd9 100644 --- a/Packages/com.unity.shadergraph/Editor/Generation/Processors/Generator.cs +++ b/Packages/com.unity.shadergraph/Editor/Generation/Processors/Generator.cs @@ -395,9 +395,6 @@ namespace UnityEditor.ShaderGraph if (m_Mode == GenerationMode.Preview) activeFields.baseInstance.Add(Fields.IsPreview); - if (m_OutputNode == null && m_Mode == GenerationMode.Preview) - activeFields.baseInstance.Add(Fields.IsMainPreview); - // Check masternode fields for valid passes if (pass.TestActive(activeFields)) GenerateShaderPass(targetIndex, pass.descriptor, activeFields, activeBlockDescriptors.Select(x => x.descriptor).ToList(), subShaderProperties); @@ -1070,6 +1067,9 @@ namespace UnityEditor.ShaderGraph { graphDefines.AppendLine("#define SHADERPASS {0}", pass.referenceName); + if (m_OutputNode == null && m_Mode == GenerationMode.Preview) + graphDefines.AppendLine("#define SHADERGRAPH_PREVIEW_MAIN"); + if (pass.defines != null) { foreach (DefineCollection.Item define in pass.defines) diff --git a/Packages/com.unity.shadergraph/Editor/Generation/TargetResources/Fields.cs b/Packages/com.unity.shadergraph/Editor/Generation/TargetResources/Fields.cs index ebc1b330..153a9ddd 100644 --- a/Packages/com.unity.shadergraph/Editor/Generation/TargetResources/Fields.cs +++ b/Packages/com.unity.shadergraph/Editor/Generation/TargetResources/Fields.cs @@ -19,7 +19,6 @@ namespace UnityEditor.ShaderGraph public static FieldDescriptor BlendAlpha = new FieldDescriptor(kBlendMode, "Alpha", "_BLENDMODE_ALPHA 1"); // URP: only sprite targets, vfx: HDRP? public static FieldDescriptor DoubleSided = new FieldDescriptor(string.Empty, "DoubleSided", "_DOUBLE_SIDED 1"); // URP: only sprite targets, duplicated in HD public static FieldDescriptor IsPreview = new FieldDescriptor(string.Empty, "isPreview", "SHADERGRAPH_PREVIEW"); - public static FieldDescriptor IsMainPreview = new FieldDescriptor(string.Empty, "isMainPreview", "SHADERGRAPH_PREVIEW_MAIN"); public static FieldDescriptor LodCrossFade = new FieldDescriptor(string.Empty, "LodCrossFade", "_LODCROSSFADE 1"); // HD only public static FieldDescriptor AlphaToMask = new FieldDescriptor(string.Empty, "AlphaToMask", "_ALPHATOMASK_ON 1"); // HD only diff --git a/Packages/com.unity.shadergraph/package.json b/Packages/com.unity.shadergraph/package.json index 51d35748..d70f5596 100644 --- a/Packages/com.unity.shadergraph/package.json +++ b/Packages/com.unity.shadergraph/package.json @@ -43,5 +43,5 @@ "path": "Samples~/UGUIShaders" } ], - "_fingerprint": "eb9759d45cf8efe237ec67f5c7c6880261fd59c4" + "_fingerprint": "26dc5ae27e7d8949b4e95045bf189b8733da88ee" } diff --git a/Packages/com.unity.ugui/Runtime/TMP/TMP_FontAsset.cs b/Packages/com.unity.ugui/Runtime/TMP/TMP_FontAsset.cs index 5f4debc1..018c9eb9 100644 --- a/Packages/com.unity.ugui/Runtime/TMP/TMP_FontAsset.cs +++ b/Packages/com.unity.ugui/Runtime/TMP/TMP_FontAsset.cs @@ -1420,8 +1420,10 @@ namespace TMPro for (int i = 0; i < text.Length; i++) { - if (!m_CharacterLookupDictionary.ContainsKey(text[i])) - missingCharacters.Add(text[i]); + uint character = TMP_FontAssetUtilities.GetCodePoint(text, ref i); + + if (!m_CharacterLookupDictionary.ContainsKey(character)) + missingCharacters.Add((char)character); } if (missingCharacters.Count == 0) @@ -1452,7 +1454,7 @@ namespace TMPro for (int i = 0; i < text.Length; i++) { bool isMissingCharacter = true; - uint character = text[i]; + uint character = TMP_FontAssetUtilities.GetCodePoint(text, ref i); if (m_CharacterLookupDictionary.ContainsKey(character)) continue; @@ -1557,7 +1559,9 @@ namespace TMPro for (int i = 0; i < text.Length; i++) { - if (!m_CharacterLookupDictionary.ContainsKey(text[i])) + uint character = TMP_FontAssetUtilities.GetCodePoint(text, ref i); + + if (!m_CharacterLookupDictionary.ContainsKey(character)) return false; } @@ -1823,7 +1827,7 @@ namespace TMPro for (int i = 0; i < unicodeCount; i++) { - uint unicode = unicodes[i]; + uint unicode = TMP_FontAssetUtilities.GetCodePoint(unicodes, ref i); // Check if character is already contained in the character table. if (m_CharacterLookupDictionary.ContainsKey(unicode)) diff --git a/Packages/com.unity.ugui/Runtime/TMP/TMP_FontAssetUtilities.cs b/Packages/com.unity.ugui/Runtime/TMP/TMP_FontAssetUtilities.cs index ffe5244b..f0e2c086 100644 --- a/Packages/com.unity.ugui/Runtime/TMP/TMP_FontAssetUtilities.cs +++ b/Packages/com.unity.ugui/Runtime/TMP/TMP_FontAssetUtilities.cs @@ -420,6 +420,48 @@ namespace TMPro return null; } + /// + /// Extracts a Unicode code point from a string at the specified index, handling surrogate pairs if present. + /// + /// The input string containing the characters to process. + /// The current index in the string. This will be incremented if a surrogate pair is found. + /// The Unicode code point at the specified index. + internal static uint GetCodePoint(string text, ref int index) + { + char c = text[index]; + if (char.IsHighSurrogate(c) + && index + 1 < text.Length + && char.IsLowSurrogate(text[index + 1])) + { + uint cp = (uint)char.ConvertToUtf32(c, text[index + 1]); + index++; + return cp; + } + + return c; + } + + /// + /// Extracts a Unicode code point from an array of uint values at the specified index, handling surrogate pairs if present. + /// + /// The array of uint values representing characters to process. + /// The current index in the array. This will be incremented if a surrogate pair is found. + /// The Unicode code point at the specified index. + internal static uint GetCodePoint(uint[] codesPoints, ref int index) + { + char c = (char)codesPoints[index]; + if (char.IsHighSurrogate(c) + && index + 1 < codesPoints.Length + && char.IsLowSurrogate((char)codesPoints[index + 1])) + { + uint cp = (uint)char.ConvertToUtf32(c, (char)codesPoints[index + 1]); + index++; + return cp; + } + + return c; + } + // ===================================================================== // FONT ENGINE & FONT FILE MANAGEMENT - Fields, Properties and Functions diff --git a/Packages/com.unity.ugui/Runtime/TMP/TMP_Text.cs b/Packages/com.unity.ugui/Runtime/TMP/TMP_Text.cs index 80294a56..25e1857d 100644 --- a/Packages/com.unity.ugui/Runtime/TMP/TMP_Text.cs +++ b/Packages/com.unity.ugui/Runtime/TMP/TMP_Text.cs @@ -1100,6 +1100,10 @@ namespace TMPro { m_IsTextObjectScaleStatic = value; + // UUM-92041. RegisterTextObjectForUpdate is not called until OnEnable. + if (!isActiveAndEnabled) + return; + if (m_IsTextObjectScaleStatic) TMP_UpdateManager.UnRegisterTextObjectForUpdate(this); else diff --git a/Packages/com.unity.ugui/Runtime/TMP/TMP_TextUtilities.cs b/Packages/com.unity.ugui/Runtime/TMP/TMP_TextUtilities.cs index f9e76e49..ed68801e 100644 --- a/Packages/com.unity.ugui/Runtime/TMP/TMP_TextUtilities.cs +++ b/Packages/com.unity.ugui/Runtime/TMP/TMP_TextUtilities.cs @@ -2023,6 +2023,11 @@ namespace TMPro /// private static bool PointIntersectRectangle(Vector3 m, Vector3 a, Vector3 b, Vector3 c, Vector3 d) { + // A zero area rectangle is not valid for this method. + Vector3 normal = Vector3.Cross(b - a, d - a); + if (normal == Vector3.zero) + return false; + Vector3 ab = b - a; Vector3 am = m - a; Vector3 bc = c - b; @@ -2116,6 +2121,13 @@ namespace TMPro /// public static float DistanceToLine(Vector3 a, Vector3 b, Vector3 point) { + // If a and b are the same point, just return distance to that point + if (a == b) + { + Vector3 diff = point - a; + return Vector3.Dot(diff, diff); + } + Vector3 n = b - a; Vector3 pa = a - point; diff --git a/Packages/com.unity.ugui/Runtime/TMP/TextMeshPro.cs b/Packages/com.unity.ugui/Runtime/TMP/TextMeshPro.cs index 85a84cdc..913e1f7e 100644 --- a/Packages/com.unity.ugui/Runtime/TMP/TextMeshPro.cs +++ b/Packages/com.unity.ugui/Runtime/TMP/TextMeshPro.cs @@ -604,8 +604,12 @@ namespace TMPro // Load TMP Settings for new text object instances. LoadDefaultSettings(); - // Load the font asset and assign material to renderer. - LoadFontAsset(); +#if UNITY_EDITOR + // We don't want to call LoadFontAsset when building the game since it causes some characters to be added to the atlas, making the build bigger. + if (!UnityEditor.BuildPipeline.isBuildingPlayer) +#endif + // Load the font asset and assign material to renderer. + LoadFontAsset(); // Allocate our initial buffers. if (m_TextProcessingArray == null) diff --git a/Packages/com.unity.ugui/Runtime/TMP/TextMeshProUGUI.cs b/Packages/com.unity.ugui/Runtime/TMP/TextMeshProUGUI.cs index a007e907..79259af3 100644 --- a/Packages/com.unity.ugui/Runtime/TMP/TextMeshProUGUI.cs +++ b/Packages/com.unity.ugui/Runtime/TMP/TextMeshProUGUI.cs @@ -823,8 +823,12 @@ namespace TMPro // Load TMP Settings for new text object instances. LoadDefaultSettings(); - // Load the font asset and assign material to renderer. - LoadFontAsset(); +#if UNITY_EDITOR + // We don't want to call LoadFontAsset when building the game since it causes some characters to be added to the atlas, making the build bigger. + if (!UnityEditor.BuildPipeline.isBuildingPlayer) +#endif + // Load the font asset and assign material to renderer. + LoadFontAsset(); // Allocate our initial buffers. if (m_TextProcessingArray == null) diff --git a/Packages/com.unity.ugui/Runtime/UGUI/EventSystem/EventSystem.cs b/Packages/com.unity.ugui/Runtime/UGUI/EventSystem/EventSystem.cs index 68dc473a..e68d294e 100644 --- a/Packages/com.unity.ugui/Runtime/UGUI/EventSystem/EventSystem.cs +++ b/Packages/com.unity.ugui/Runtime/UGUI/EventSystem/EventSystem.cs @@ -383,7 +383,7 @@ namespace UnityEngine.EventSystems if (sendEvents) { var eventSystem = activeEventSystem != null ? activeEventSystem : EventSystem.current; - if (eventSystem.isActiveAndEnabled) + if (eventSystem != null && eventSystem.isActiveAndEnabled) UIElementsRuntimeUtility.RegisterEventSystem(activeEventSystem); } #endif @@ -392,6 +392,7 @@ namespace UnityEngine.EventSystems #if PACKAGE_UITOOLKIT private bool m_Started; private bool m_IsTrackingUIToolkitPanels; + private List m_NewPanels = new(); private void StartTrackingUIToolkitPanels() { @@ -401,7 +402,7 @@ namespace UnityEngine.EventSystems { CreateUIToolkitPanelGameObject(panel); } - UIElementsRuntimeUtility.onCreatePanel += CreateUIToolkitPanelGameObject; + UIElementsRuntimeUtility.onCreatePanel += m_NewPanels.Add; m_IsTrackingUIToolkitPanels = true; } } @@ -410,11 +411,20 @@ namespace UnityEngine.EventSystems { if (m_IsTrackingUIToolkitPanels) { - UIElementsRuntimeUtility.onCreatePanel -= CreateUIToolkitPanelGameObject; + UIElementsRuntimeUtility.onCreatePanel -= m_NewPanels.Add; m_IsTrackingUIToolkitPanels = false; } } + private void UpdatePanelGameObjects() + { + foreach (var panel in m_NewPanels) + { + CreateUIToolkitPanelGameObject(panel); + } + m_NewPanels.Clear(); + } + private void CreateUIToolkitPanelGameObject(BaseRuntimePanel panel) { if (panel.selectableGameObject == null) @@ -422,7 +432,7 @@ namespace UnityEngine.EventSystems var go = new GameObject(panel.name, typeof(PanelEventHandler), typeof(PanelRaycaster)); go.transform.SetParent(transform); panel.selectableGameObject = go; - panel.destroyed += () => DestroyImmediate(go); + panel.destroyed += () => UIRUtility.Destroy(go); } } #endif @@ -491,6 +501,10 @@ namespace UnityEngine.EventSystems protected virtual void Update() { +#if PACKAGE_UITOOLKIT + UpdatePanelGameObjects(); +#endif + if (current != this) return; TickModules(); diff --git a/Packages/com.unity.ugui/Runtime/UGUI/EventSystem/UIElements/PanelEventHandler.cs b/Packages/com.unity.ugui/Runtime/UGUI/EventSystem/UIElements/PanelEventHandler.cs index 62b1f796..7ed2b9d5 100644 --- a/Packages/com.unity.ugui/Runtime/UGUI/EventSystem/UIElements/PanelEventHandler.cs +++ b/Packages/com.unity.ugui/Runtime/UGUI/EventSystem/UIElements/PanelEventHandler.cs @@ -281,7 +281,11 @@ namespace UnityEngine.UIElements // See UGUIEventSystemTests.KeyDownStoppedDoesntPreventNavigationEvents for a test requires this. } - internal void Update() + /// + /// This method is automatically called on every frame. + /// It can also be called manually to force some queued events to be processed. + /// + public void Update() { if (isCurrentFocusedPanel) ProcessImguiEvents(currentFocusedElement ?? m_Panel.visualTree); diff --git a/Packages/com.unity.ugui/Runtime/UGUI/UI/Core/MultipleDisplayUtilities.cs b/Packages/com.unity.ugui/Runtime/UGUI/UI/Core/MultipleDisplayUtilities.cs index 24b75ead..e7198883 100644 --- a/Packages/com.unity.ugui/Runtime/UGUI/UI/Core/MultipleDisplayUtilities.cs +++ b/Packages/com.unity.ugui/Runtime/UGUI/UI/Core/MultipleDisplayUtilities.cs @@ -132,7 +132,7 @@ namespace UnityEngine.UI // fix for UUM-63551: Use the display index provided to this method. Display.RelativeMouseAt( ) no longer works starting with 2021 LTS and new input system // as the Pointer position is reported in Window coordinates rather than relative to the primary window as Display.RelativeMouseAt( ) expects. -#if ENABLE_INPUT_SYSTEM && PACKAGE_INPUTSYSTEM && (UNITY_STANDALONE_WIN || UNITY_STANDALONE_LINUX || UNITY_ANDROID) +#if ENABLE_INPUT_SYSTEM && PACKAGE_INPUTSYSTEM && (UNITY_STANDALONE_WIN || UNITY_STANDALONE_LINUX || UNITY_ANDROID || UNITY_EMBEDDED_LINUX || UNITY_QNX) var relativePos = new Vector3(adjustedPosition.x, adjustedPosition.y, displayIndex); #else var relativePos = Display.RelativeMouseAt(adjustedPosition); @@ -144,7 +144,7 @@ namespace UnityEngine.UI } // We are using the main display. -#if ENABLE_INPUT_SYSTEM && PACKAGE_INPUTSYSTEM && UNITY_ANDROID +#if ENABLE_INPUT_SYSTEM && PACKAGE_INPUTSYSTEM && (UNITY_ANDROID || UNITY_EMBEDDED_LINUX || UNITY_QNX) // On Android, in all cases, it is a surface associated to a given displayIndex, so we need to use the display index return new Vector3(position.x, position.y, displayIndex); #else @@ -155,7 +155,7 @@ namespace UnityEngine.UI // fix for UUM-63551: Use the display index provided to this method. Display.RelativeMouseAt( ) no longer works starting with 2021 LTS and new input system // as the Pointer position is reported in Window coordinates rather than relative to the primary window as Display.RelativeMouseAt( ) expects. -#if ENABLE_INPUT_SYSTEM && PACKAGE_INPUTSYSTEM && (UNITY_STANDALONE_WIN || UNITY_STANDALONE_LINUX || UNITY_ANDROID) +#if ENABLE_INPUT_SYSTEM && PACKAGE_INPUTSYSTEM && (UNITY_STANDALONE_WIN || UNITY_STANDALONE_LINUX || UNITY_ANDROID || UNITY_EMBEDDED_LINUX || UNITY_QNX) return new Vector3(position.x, position.y, displayIndex); #else return Display.RelativeMouseAt(position); diff --git a/Packages/com.unity.ugui/Tests/Runtime/TMP/TMP_RuntimeTests.cs b/Packages/com.unity.ugui/Tests/Runtime/TMP/TMP_RuntimeTests.cs index ef20ef65..ac4ec002 100644 --- a/Packages/com.unity.ugui/Tests/Runtime/TMP/TMP_RuntimeTests.cs +++ b/Packages/com.unity.ugui/Tests/Runtime/TMP/TMP_RuntimeTests.cs @@ -4,6 +4,7 @@ using System.IO; using System.Collections.Generic; using UnityEngine.UI; using UnityEngine.EventSystems; +using UnityEngine.TestTools; namespace TMPro { @@ -274,5 +275,57 @@ namespace TMPro // } //} + [Test] + public void SettingIsTextObjectScaleStatic_OnDisabledObject_DoesntProduceErrors() + { + // Reset the text component to before its OnEnable + var textObject = m_TextComponent.gameObject; + Object.DestroyImmediate(m_TextComponent); + textObject.SetActive(false); + m_TextComponent = textObject.AddComponent(); + + // UUM-92041: verify that we only register if enabled + m_TextComponent.isTextObjectScaleStatic = true; // Make sure we're not starting false + m_TextComponent.isTextObjectScaleStatic = false; + Canvas.ForceUpdateCanvases(); + + LogAssert.NoUnexpectedReceived(); + } + + [Test] + public void SettingIsTextObjectScaleStatic_OnDisabledObject_IsAppliedCorrectlyAfterObjectIsEnabled() + { + m_TextComponent.text = "Test"; + + // Reset the text component to before its OnEnable + var textObject = m_TextComponent.gameObject; + Object.DestroyImmediate(m_TextComponent); + textObject.SetActive(false); + m_TextComponent = textObject.AddComponent(); + + // Set isTextObjectScaleStatic to false while the object is disabled + m_TextComponent.isTextObjectScaleStatic = true; + m_TextComponent.isTextObjectScaleStatic = false; // Make sure we're not starting false + Canvas.ForceUpdateCanvases(); + + m_TextComponent.gameObject.SetActive(true); + Canvas.ForceUpdateCanvases(); + var w = m_TextComponent.textInfo.meshInfo[0].uvs0[0].w; + + // When isTextObjectScaleStatic is false, scale is updated in mesh uv + m_TextComponent.transform.localScale = Vector3.one * 2; + Canvas.ForceUpdateCanvases(); + Assert.AreEqual(w * 2, m_TextComponent.textInfo.meshInfo[0].uvs0[0].w); + + // Setting isTextObjectScaleStatic to true shouldn't change mesh + m_TextComponent.isTextObjectScaleStatic = true; + Canvas.ForceUpdateCanvases(); + Assert.AreEqual(w * 2, m_TextComponent.textInfo.meshInfo[0].uvs0[0].w); + + // When isTextObjectScaleStatic is true, scale is NOT updated in mesh + m_TextComponent.transform.localScale = Vector3.one; + Canvas.ForceUpdateCanvases(); + Assert.AreEqual(w * 2, m_TextComponent.textInfo.meshInfo[0].uvs0[0].w); + } } } diff --git a/Packages/com.unity.ugui/package.json b/Packages/com.unity.ugui/package.json index d7b501b6..b5d16449 100644 --- a/Packages/com.unity.ugui/package.json +++ b/Packages/com.unity.ugui/package.json @@ -19,5 +19,5 @@ "com.unity.modules.ui": "1.0.0", "com.unity.modules.imgui": "1.0.0" }, - "_fingerprint": "77ab6c14086a78be39959c143506f2d27f70c4e3" + "_fingerprint": "5c9fd4989cdd8e57279d95edb174435a77f5c853" } diff --git a/Packages/com.unity.visualeffectgraph/Editor/Models/Contexts/Implementations/VFXMeshOutput.cs b/Packages/com.unity.visualeffectgraph/Editor/Models/Contexts/Implementations/VFXMeshOutput.cs index 7c79577d..bba2f6ed 100644 --- a/Packages/com.unity.visualeffectgraph/Editor/Models/Contexts/Implementations/VFXMeshOutput.cs +++ b/Packages/com.unity.visualeffectgraph/Editor/Models/Contexts/Implementations/VFXMeshOutput.cs @@ -29,7 +29,7 @@ namespace UnityEditor.VFX VFXOutputUpdate.Features features = base.outputUpdateFeatures; if (!HasStrips(true)) // TODO make it compatible with strips { - if (MeshCount > 1) + if (meshCount > 1) features |= VFXOutputUpdate.Features.MultiMesh; if (lod) features |= VFXOutputUpdate.Features.LOD; @@ -60,7 +60,7 @@ namespace UnityEditor.VFX foreach (var property in base.inputProperties) yield return property; - foreach (var property in VFXMultiMeshHelper.GetInputProperties(MeshCount, outputUpdateFeatures)) + foreach (var property in VFXMultiMeshHelper.GetInputProperties(meshCount, outputUpdateFeatures)) yield return property; if (GetOrRefreshShaderGraphObject() == null) @@ -116,7 +116,7 @@ namespace UnityEditor.VFX { case VFXDeviceTarget.CPU: { - foreach (var name in VFXMultiMeshHelper.GetCPUExpressionNames(MeshCount)) + foreach (var name in VFXMultiMeshHelper.GetCPUExpressionNames(meshCount)) mapper.AddExpression(inputSlots.First(s => s.name == name).GetExpression(), name, -1); break; } diff --git a/Packages/com.unity.visualeffectgraph/Editor/Models/Contexts/VFXAbstractParticleOutput.cs b/Packages/com.unity.visualeffectgraph/Editor/Models/Contexts/VFXAbstractParticleOutput.cs index 09a4c73f..290a8708 100644 --- a/Packages/com.unity.visualeffectgraph/Editor/Models/Contexts/VFXAbstractParticleOutput.cs +++ b/Packages/com.unity.visualeffectgraph/Editor/Models/Contexts/VFXAbstractParticleOutput.cs @@ -143,7 +143,19 @@ namespace UnityEditor.VFX public virtual void SetupMaterial(Material material) { } - public bool HasIndirectDraw() { return (indirectDraw || HasSorting() || VFXOutputUpdate.HasFeature(outputUpdateFeatures, VFXOutputUpdate.Features.IndirectDraw)); } + protected bool HasUpdateInputContext() + { + foreach (var inputContext in inputContexts) + { + if (inputContext.contextType.HasFlag(VFXContextType.Update)) + { + return true; + } + } + return false; + } + + public bool HasIndirectDraw() { return ((indirectDraw && HasUpdateInputContext()) || HasSorting() || VFXOutputUpdate.HasFeature(outputUpdateFeatures, VFXOutputUpdate.Features.IndirectDraw)); } public virtual bool HasSorting() { return sort == SortActivationMode.On || (sort == SortActivationMode.Auto && (blendMode == BlendMode.Alpha || blendMode == BlendMode.AlphaPremultiplied)); } public bool HasCustomSortingCriterion() { return HasSorting() && sortMode == VFXSortingUtility.SortCriteria.Custom; } @@ -636,7 +648,7 @@ namespace UnityEditor.VFX yield return "useExposureWeight"; // indirect draw is implicit or forbidden - if (HasSorting() || VFXOutputUpdate.HasFeature(outputUpdateFeatures, VFXOutputUpdate.Features.IndirectDraw)) + if (!HasUpdateInputContext() || HasSorting() || VFXOutputUpdate.HasFeature(outputUpdateFeatures, VFXOutputUpdate.Features.IndirectDraw)) yield return "indirectDraw"; // compute culling is implicit or forbidden diff --git a/Packages/com.unity.visualeffectgraph/Editor/ShaderGraph/Templates/VFXConfigPlanarPrimitive.template.hlsl b/Packages/com.unity.visualeffectgraph/Editor/ShaderGraph/Templates/VFXConfigPlanarPrimitive.template.hlsl index b72648b5..a3907bd9 100644 --- a/Packages/com.unity.visualeffectgraph/Editor/ShaderGraph/Templates/VFXConfigPlanarPrimitive.template.hlsl +++ b/Packages/com.unity.visualeffectgraph/Editor/ShaderGraph/Templates/VFXConfigPlanarPrimitive.template.hlsl @@ -42,7 +42,8 @@ bool GetMeshAndElementIndex(inout VFX_SRP_ATTRIBUTES input, inout AttributesElem StripData stripData; uint relativeIndexInStrip = 0; #if HAS_STRIPS - if (!FindIndexInStrip(index, id, instanceIndex, relativeIndexInStrip, stripData)) + uint primitiveId = id; + if (!FindIndexInStrip(index, primitiveId, instanceIndex, relativeIndexInStrip, stripData)) return false; #else stripData = GetStripDataFromParticleIndex(index, instanceIndex); diff --git a/Packages/com.unity.visualeffectgraph/Shaders/VFXParticleCommon.template b/Packages/com.unity.visualeffectgraph/Shaders/VFXParticleCommon.template index bd20f53e..e1009c0e 100644 --- a/Packages/com.unity.visualeffectgraph/Shaders/VFXParticleCommon.template +++ b/Packages/com.unity.visualeffectgraph/Shaders/VFXParticleCommon.template @@ -170,7 +170,12 @@ index = indirectBuffer[VFXGetIndirectBufferIndex(index, instanceActiveIndex)]; #if HAS_STRIPS_DATA StripData stripData; uint relativeIndexInStrip = 0; -if (!FindIndexInStrip(index, id, instanceIndex, relativeIndexInStrip, stripData)) +uint primitiveID = 0; +#if HAS_STRIPS + primitiveID = id; +#endif + +if (!FindIndexInStrip(index, primitiveID, instanceIndex, relativeIndexInStrip, stripData)) { CULL_VERTEX(o); } diff --git a/Packages/com.unity.visualeffectgraph/package.json b/Packages/com.unity.visualeffectgraph/package.json index b4ca5c81..737f8f3a 100644 --- a/Packages/com.unity.visualeffectgraph/package.json +++ b/Packages/com.unity.visualeffectgraph/package.json @@ -36,5 +36,5 @@ ] } ], - "_fingerprint": "d36b3d483f5612a567e3133ff295597009bdc4a6" + "_fingerprint": "a6f52bdb90a859536ffa7087989628316309dacc" }