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 622b7f25..fc3cba2e 100644
--- a/Packages/com.unity.render-pipelines.core/Tests/Editor/NativePassCompilerRenderGraphTests.cs
+++ b/Packages/com.unity.render-pipelines.core/Tests/Editor/NativePassCompilerRenderGraphTests.cs
@@ -1414,5 +1414,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"
}