Ejemplo n.º 1
0
        /// <summary>
        /// Compute a hash of the settings.
        /// </summary>
        /// <returns>The computed hash.</returns>
        public Hash128 ComputeHash()
        {
            var h  = new Hash128();
            var h2 = new Hash128();

            HashUtilities.ComputeHash128(ref type, ref h);
            HashUtilities.ComputeHash128(ref mode, ref h2);
            HashUtilities.AppendHash(ref h2, ref h);
            HashUtilities.ComputeHash128(ref lighting, ref h2);
            HashUtilities.AppendHash(ref h2, ref h);
            HashUtilities.ComputeHash128(ref proxySettings, ref h2);
            HashUtilities.AppendHash(ref h2, ref h);
            HashUtilities.ComputeHash128(ref cameraSettings, ref h2);
            HashUtilities.AppendHash(ref h2, ref h);
            if (influence != null)
            {
                h2 = influence.ComputeHash();
                HashUtilities.AppendHash(ref h2, ref h);
            }
            if (proxy != null)
            {
                h2 = proxy.ComputeHash();
                HashUtilities.AppendHash(ref h2, ref h);
            }
            return(h);
        }
Ejemplo n.º 2
0
#pragma warning restore 618

        internal Hash128 GetHash()
        {
            var h  = new Hash128();
            var h2 = new Hash128();

            HashUtilities.ComputeHash128(ref bufferClearing, ref h);
            HashUtilities.ComputeHash128(ref culling, ref h2);
            HashUtilities.AppendHash(ref h2, ref h);
            HashUtilities.ComputeHash128(ref customRenderingSettings, ref h2);
            HashUtilities.AppendHash(ref h2, ref h);
            HashUtilities.ComputeHash128(ref defaultFrameSettings, ref h2);
            HashUtilities.AppendHash(ref h2, ref h);
            HashUtilities.ComputeHash128(ref flipYMode, ref h2);
            HashUtilities.AppendHash(ref h2, ref h);
            HashUtilities.ComputeHash128(ref frustum, ref h2);
            HashUtilities.AppendHash(ref h2, ref h);
            HashUtilities.ComputeHash128(ref invertFaceCulling, ref h2);
            HashUtilities.AppendHash(ref h2, ref h);
            HashUtilities.ComputeHash128(ref probeLayerMask, ref h2);
            HashUtilities.AppendHash(ref h2, ref h);
            HashUtilities.ComputeHash128(ref probeRangeCompressionFactor, ref h2);
            HashUtilities.AppendHash(ref h2, ref h);
            HashUtilities.ComputeHash128(ref renderingPathCustomFrameSettings, ref h2);
            HashUtilities.AppendHash(ref h2, ref h);
            HashUtilities.ComputeHash128(ref renderingPathCustomFrameSettingsOverrideMask, ref h2);
            HashUtilities.AppendHash(ref h2, ref h);
            int volumeHash = volumes.GetHashCode();

            h2 = new Hash128((ulong)volumeHash, 0);
            HashUtilities.AppendHash(ref h2, ref h);

            return(h);
        }
Ejemplo n.º 3
0
        public override int GetHashCode()
        {
            var h = new Hash128();

            HashUtilities.AppendHash(ref m_SceneObjectsHash, ref h);
            HashUtilities.AppendHash(ref m_SkySettingsHash, ref h);
            HashUtilities.AppendHash(ref m_AmbientProbeHash, ref h);
            return(h.GetHashCode());
        }
Ejemplo n.º 4
0
        internal static Hash128 CreateWindowAndStageIdentifier(string windowGUID, Stage stage)
        {
            Hash128 hash          = stage.GetHashForStateStorage();
            Hash128 windowHash    = Hash128.Compute(windowGUID);
            Hash128 stageTypeHash = Hash128.Compute(stage.GetType().FullName);

            HashUtilities.AppendHash(ref windowHash, ref hash);
            HashUtilities.AppendHash(ref stageTypeHash, ref hash);
            return(hash);
        }
    public static Hash128 NUVHash(Vector3 n, Vector2 uv)
    {
        Hash128 res = new Hash128();

        HashUtilities.QuantisedVectorHash(ref n, ref res);
        Hash128 uvHash = new Hash128();
        Vector3 uv3    = new Vector3(uv.x, uv.y, 0.0f);

        HashUtilities.QuantisedVectorHash(ref uv3, ref uvHash);
        HashUtilities.AppendHash(ref uvHash, ref res);
        return(res);
    }
 static void ComputeProbeSettingsHashes(IList <HDProbe> probes, HDProbeBakingState *states)
 {
     for (int i = 0; i < probes.Count; ++i)
     {
         var probe                = probes[i];
         var positionSettings     = ProbeCapturePositionSettings.ComputeFrom(probe, null);
         var positionSettingsHash = positionSettings.ComputeHash();
         // TODO: make ProbeSettings and unmanaged type so its hash can be the hash of its memory
         var probeSettingsHash = probe.settings.ComputeHash();
         HashUtilities.AppendHash(ref positionSettingsHash, ref probeSettingsHash);
         states[i].probeSettingsHash = probeSettingsHash;
     }
 }
        /// <summary>Combine all of the hashes of a collection of hashes.</summary>
        /// <typeparam name="TValue">Value type.</typeparam>
        /// <typeparam name="TGetter">Getter type.</typeparam>
        /// <param name="count">Number of hash to combine.</param>
        /// <param name="hashes">Hashes to combine.</param>
        /// <param name="outHash">Hash to update.</param>
        public static void CombineHashes <TValue, TGetter>(int count, void *hashes, Hash128 *outHash)
            where TValue : struct
            where TGetter : struct, IKeyGetter <TValue, Hash128>
        {
            var getter = new TGetter();

            for (int i = 0; i < count; ++i)
            {
                var v = UnsafeUtility.ReadArrayElement <TValue>(hashes, i);
                var h = getter.Get(ref v);
                HashUtilities.AppendHash(ref h, ref *outHash);
            }
        }
Ejemplo n.º 8
0
        static void ComputeProbeSettingsHashes(IEnumerable <HDProbe> probes, HDProbeBakingState *states)
        {
            var i = 0;

            foreach (var probe in probes)
            {
                var positionSettings     = ProbeCapturePositionSettings.ComputeFrom(probe, null);
                var positionSettingsHash = positionSettings.ComputeHash();
                // TODO: make ProbeSettings and unmanaged type so its hash can be the hash of its memory
                var probeSettingsHash = probe.settings.ComputeHash();
                HashUtilities.AppendHash(ref positionSettingsHash, ref probeSettingsHash);
                states[i].probeSettingsHash = probeSettingsHash;
                ++i;
            }
        }
Ejemplo n.º 9
0
        public static Hash128 RefreshCustomIndexers()
        {
            Hash128 globalIndexersHash = default;

            foreach (var customIndexerMethodInfo in TypeCache.GetMethodsWithAttribute <CustomObjectIndexerAttribute>())
            {
                var name = $"{customIndexerMethodInfo.DeclaringType.FullName}.{customIndexerMethodInfo.Name}";
                if (SearchSettings.disabledIndexers.Contains(name))
                {
                    continue;
                }

                try
                {
                    var customIndexerAttribute = customIndexerMethodInfo.GetCustomAttribute <CustomObjectIndexerAttribute>();
                    var indexerType            = customIndexerAttribute.type;
                    if (indexerType == null)
                    {
                        continue;
                    }

                    if (!ValidateCustomIndexerMethodSignature(customIndexerMethodInfo))
                    {
                        continue;
                    }

                    if (!(Delegate.CreateDelegate(typeof(CustomIndexerHandler), customIndexerMethodInfo) is CustomIndexerHandler customIndexerAction))
                    {
                        continue;
                    }

                    if (!s_CustomObjectIndexers.TryGetValue(indexerType, out var indexerList))
                    {
                        indexerList = new List <CustomIndexerHandler>();
                        s_CustomObjectIndexers.Add(indexerType, indexerList);
                    }
                    indexerList.Add(customIndexerAction);

                    var customIndexerHash = ComputeCustomIndexerHash(customIndexerMethodInfo, customIndexerAttribute);
                    HashUtilities.AppendHash(ref customIndexerHash, ref globalIndexersHash);
                }
                catch (Exception ex)
                {
                    Debug.LogWarning($"Cannot load CustomObjectIndexer with method: {customIndexerMethodInfo.Name} ({ex.Message})");
                }
            }
            return(globalIndexersHash);
        }
        void ImportXml(string xmlPath, out VisualTreeAsset vta)
        {
            vta = ScriptableObject.CreateInstance <VisualTreeAsset>();
            vta.visualElementAssets = new List <VisualElementAsset>();
            vta.templateAssets      = new List <TemplateAsset>();

            var h = new Hash128();

            using (var stream = File.OpenRead(xmlPath))
            {
                int    readCount = 0;
                byte[] b         = new byte[1024 * 16];
                while ((readCount = stream.Read(b, 0, b.Length)) > 0)
                {
                    for (int i = readCount; i < b.Length; i++)
                    {
                        b[i] = 0;
                    }
                    Hash128 blockHash = new Hash128();
                    HashUtilities.ComputeHash128(b, ref blockHash);
                    HashUtilities.AppendHash(ref blockHash, ref h);
                }
            }

            vta.contentHash = h.GetHashCode();

            XDocument doc;

            try
            {
                doc = XDocument.Load(xmlPath, LoadOptions.SetLineInfo);
            }
            catch (Exception e)
            {
                logger.LogError(ImportErrorType.Syntax, ImportErrorCode.InvalidXml, e, Error.Level.Fatal, null);
                return;
            }

            LoadXmlRoot(doc, vta);

            StyleSheet inlineSheet = ScriptableObject.CreateInstance <StyleSheet>();

            inlineSheet.name = "inlineStyle";
            m_Builder.BuildTo(inlineSheet);
            vta.inlineSheet = inlineSheet;
        }
Ejemplo n.º 11
0
        public Hash128 ComputeHash()
        {
            var h  = new Hash128();
            var h2 = new Hash128();

            HashUtilities.QuantisedVectorHash(ref proxyPosition, ref h);
            HashUtilities.QuantisedVectorHash(ref referencePosition, ref h2);
            HashUtilities.AppendHash(ref h2, ref h);
            var euler = proxyRotation.eulerAngles;

            HashUtilities.QuantisedVectorHash(ref euler, ref h2);
            HashUtilities.AppendHash(ref h2, ref h);
            euler = referenceRotation.eulerAngles;
            HashUtilities.QuantisedVectorHash(ref euler, ref h2);
            HashUtilities.AppendHash(ref h2, ref h);
            return(h);
        }
Ejemplo n.º 12
0
            public void Append(float[] values, int count)
            {
                if (values == null)
                {
                    return;
                }

                // Pre-2020 versions of Unity don't have Hash128.Append() (can only hash strings and scalars)
                // For these versions, we'll hash element by element.
#if UNITY_2020_1_OR_NEWER
                m_Hash.Append(values, 0, count);
#else
                for (var i = 0; i < count; i++)
                {
                    var tempHash = new Hash128();
                    HashUtilities.ComputeHash128(ref values[i], ref tempHash);
                    HashUtilities.AppendHash(ref tempHash, ref m_Hash);
                }
#endif
            }
        static void LoadCustomObjectIndexers()
        {
            Hash128 globalIndexersHash = default;

            foreach (var customIndexerMethodInfo in Utils.GetAllMethodsWithAttribute <CustomObjectIndexerAttribute>())
            {
                var customIndexerAttribute = customIndexerMethodInfo.GetCustomAttribute <CustomObjectIndexerAttribute>();
                var indexerType            = customIndexerAttribute.type;
                if (indexerType == null)
                {
                    continue;
                }

                if (!ValidateCustomIndexerMethodSignature(customIndexerMethodInfo))
                {
                    continue;
                }

                if (!(Delegate.CreateDelegate(typeof(CustomIndexerHandler), customIndexerMethodInfo) is CustomIndexerHandler customIndexerAction))
                {
                    continue;
                }

                if (!s_CustomObjectIndexers.TryGetValue(indexerType, out var indexerList))
                {
                    indexerList = new List <CustomIndexerHandler>();
                    s_CustomObjectIndexers.Add(indexerType, indexerList);
                }
                indexerList.Add(customIndexerAction);

                var customIndexerHash = ComputeCustomIndexerHash(customIndexerMethodInfo, customIndexerAttribute);
                HashUtilities.AppendHash(ref customIndexerHash, ref globalIndexersHash);
            }

            #if UNITY_2020_1_OR_NEWER
            if (!AssetDatabaseAPI.IsAssetImportWorkerProcess())
            {
                EditorApplication.delayCall += () => AssetDatabaseAPI.RegisterCustomDependency(nameof(CustomObjectIndexerAttribute), globalIndexersHash);
            }
            #endif
        }
Ejemplo n.º 14
0
        void ImportXml(string xmlPath, out VisualTreeAsset vta)
        {
            var h = new Hash128();

            using (var stream = File.OpenRead(xmlPath))
            {
                int    readCount = 0;
                byte[] b         = new byte[1024 * 16];
                while ((readCount = stream.Read(b, 0, b.Length)) > 0)
                {
                    for (int i = readCount; i < b.Length; i++)
                    {
                        b[i] = 0;
                    }
                    Hash128 blockHash = new Hash128();
                    HashUtilities.ComputeHash128(b, ref blockHash);
                    HashUtilities.AppendHash(ref blockHash, ref h);
                }
            }

            CreateVisualTreeAsset(out vta, h);

            XDocument doc;

            try
            {
                doc = XDocument.Load(xmlPath, LoadOptions.SetLineInfo);
            }
            catch (Exception e)
            {
                logger.LogError(ImportErrorType.Syntax, ImportErrorCode.InvalidXml, e, Error.Level.Fatal, null);
                return;
            }

            LoadXmlRoot(doc, vta);
            TryCreateInlineStyleSheet(vta);
        }
Ejemplo n.º 15
0
            public void Append(string value)
            {
                var tempHash = Hash128.Compute(value);

                HashUtilities.AppendHash(ref tempHash, ref m_Hash);
            }
        public override void Tick(
            SceneStateHash sceneStateHash,
            IScriptableBakedReflectionSystemStageNotifier handle
            )
        {
            if (!AreAllOpenedSceneSaved())
            {
                handle.SetIsDone(true);
                return;
            }

            // On the C# side, we don't have non blocking asset import APIs, and we don't want to block the
            //   UI when the user is editing the world.
            //   So, we skip the baking when the user is editing any UI control.
            if (GUIUtility.hotControl != 0)
            {
                return;
            }

            if (!IsCurrentSRPValid(out HDRenderPipeline hdPipeline))
            {
                if (ShouldIssueWarningForCurrentSRP())
                {
                    Debug.LogWarning("HDBakedReflectionSystem work with HDRP, " +
                                     "please switch your render pipeline or use another reflection system");
                }

                handle.ExitStage((int)BakingStages.ReflectionProbes);
                handle.SetIsDone(true);
                return;
            }

            var ambientProbeHash = sceneStateHash.ambientProbeHash;
            var sceneObjectsHash = sceneStateHash.sceneObjectsHash;
            var skySettingsHash  = sceneStateHash.skySettingsHash;

            DeleteCubemapAssets(true);

            // Explanation of the algorithm:
            // 1. First we create the hash of the world that can impact the reflection probes.
            // 2. Then for each probe, we calculate a hash that represent what this specific probe should have baked.
            // 3. We compare those hashes against the baked one and decide:
            //   a. If we have to remove a baked data
            //   b. If we have to bake a probe
            // 4. Bake all required probes
            // 5. Remove unused baked data
            // 6. Update probe assets

            // == 1. ==
            var allProbeDependencyHash = new Hash128();

            // TODO: All baked probes depend on custom probes (hash all custom probes and set as dependency)
            // TODO: All baked probes depend on HDRP specific Light settings
            HashUtilities.AppendHash(ref ambientProbeHash, ref allProbeDependencyHash);
            HashUtilities.AppendHash(ref sceneObjectsHash, ref allProbeDependencyHash);
            HashUtilities.AppendHash(ref skySettingsHash, ref allProbeDependencyHash);

            var bakedProbes = HDProbeSystem.bakedProbes;

            // == 2. ==
            var states = stackalloc HDProbeBakingState[bakedProbes.Count];

            ComputeProbeInstanceID(bakedProbes, states);
            ComputeProbeSettingsHashes(bakedProbes, states);
            // TODO: Handle bounce dependency here
            ComputeProbeBakingHashes(bakedProbes.Count, allProbeDependencyHash, states);

            CoreUnsafeUtils.QuickSort <HDProbeBakingState, Hash128, HDProbeBakingState.ProbeBakingHash>(
                bakedProbes.Count, states
                );

            int operationCount = 0, addCount = 0, remCount = 0;
            var maxProbeCount = Mathf.Max(bakedProbes.Count, m_HDProbeBakedStates.Length);
            var addIndices    = stackalloc int[maxProbeCount];
            var remIndices    = stackalloc int[maxProbeCount];

            if (m_HDProbeBakedStates.Length == 0)
            {
                for (int i = 0; i < bakedProbes.Count; ++i)
                {
                    addIndices[addCount++] = i;
                }
                operationCount = addCount;
            }
            else
            {
                fixed(HDProbeBakedState *oldBakedStates = &m_HDProbeBakedStates[0])
                {
                    // == 3. ==
                    // Compare hashes between baked probe states and desired probe states
                    operationCount = CoreUnsafeUtils.CompareHashes <
                        HDProbeBakedState, HDProbeBakedState.ProbeBakedHash,
                        HDProbeBakingState, HDProbeBakingState.ProbeBakingHash
                        > (
                        m_HDProbeBakedStates.Length, oldBakedStates, // old hashes
                        bakedProbes.Count, states,                   // new hashes
                        addIndices, remIndices,
                        out addCount, out remCount
                        );
                }
            }

            if (operationCount > 0)
            {
                // == 4. ==
                var cubemapSize = (int)hdPipeline.currentPlatformRenderPipelineSettings.lightLoopSettings.reflectionCubemapSize;
                var planarSize  = (int)hdPipeline.currentPlatformRenderPipelineSettings.lightLoopSettings.planarReflectionTextureSize;
                var cubeRT      = HDRenderUtilities.CreateReflectionProbeRenderTarget(cubemapSize);
                var planarRT    = HDRenderUtilities.CreatePlanarProbeRenderTarget(planarSize);

                handle.EnterStage(
                    (int)BakingStages.ReflectionProbes,
                    string.Format("Reflection Probes | {0} jobs", addCount),
                    0
                    );

                // Render probes
                for (int i = 0; i < addCount; ++i)
                {
                    handle.EnterStage(
                        (int)BakingStages.ReflectionProbes,
                        string.Format("Reflection Probes | {0} jobs", addCount),
                        i / (float)addCount
                        );

                    var index      = addIndices[i];
                    var instanceId = states[index].instanceID;
                    var probe      = (HDProbe)EditorUtility.InstanceIDToObject(instanceId);
                    var cacheFile  = GetGICacheFileForHDProbe(states[index].probeBakingHash);

                    // Get from cache or render the probe
                    if (!File.Exists(cacheFile))
                    {
                        RenderAndWriteToFile(probe, cacheFile, cubeRT, planarRT);
                    }
                }
                cubeRT.Release();
                planarRT.Release();

                // Copy texture from cache
                for (int i = 0; i < addCount; ++i)
                {
                    var index      = addIndices[i];
                    var instanceId = states[index].instanceID;
                    var probe      = (HDProbe)EditorUtility.InstanceIDToObject(instanceId);
                    var cacheFile  = GetGICacheFileForHDProbe(states[index].probeBakingHash);

                    Assert.IsTrue(File.Exists(cacheFile));

                    var bakedTexturePath = HDBakingUtilities.GetBakedTextureFilePath(probe);
                    HDBakingUtilities.CreateParentDirectoryIfMissing(bakedTexturePath);
                    Checkout(bakedTexturePath);
                    // Checkout will make those file writeable, but this is not immediate,
                    // so we retries when this fails.
                    if (!HDEditorUtils.CopyFileWithRetryOnUnauthorizedAccess(cacheFile, bakedTexturePath))
                    {
                        return;
                    }
                }
                // AssetPipeline bug
                // Sometimes, the baked texture reference is destroyed during 'AssetDatabase.StopAssetEditing()'
                //   thus, the reference to the baked texture in the probe is lost
                // Although, importing twice the texture seems to workaround the issue
                for (int j = 0; j < 2; ++j)
                {
                    AssetDatabase.StartAssetEditing();
                    for (int i = 0; i < bakedProbes.Count; ++i)
                    {
                        var index            = addIndices[i];
                        var instanceId       = states[index].instanceID;
                        var probe            = (HDProbe)EditorUtility.InstanceIDToObject(instanceId);
                        var bakedTexturePath = HDBakingUtilities.GetBakedTextureFilePath(probe);
                        AssetDatabase.ImportAsset(bakedTexturePath);
                        ImportAssetAt(probe, bakedTexturePath);
                    }
                    AssetDatabase.StopAssetEditing();
                }
                // Import assets
                AssetDatabase.StartAssetEditing();
                for (int i = 0; i < addCount; ++i)
                {
                    var index            = addIndices[i];
                    var instanceId       = states[index].instanceID;
                    var probe            = (HDProbe)EditorUtility.InstanceIDToObject(instanceId);
                    var bakedTexturePath = HDBakingUtilities.GetBakedTextureFilePath(probe);
                    var bakedTexture     = AssetDatabase.LoadAssetAtPath <Texture>(bakedTexturePath);
                    Assert.IsNotNull(bakedTexture, "The baked texture was imported before, " +
                                     "so it must exists in AssetDatabase");

                    probe.SetTexture(ProbeSettings.Mode.Baked, bakedTexture);
                    EditorUtility.SetDirty(probe);
                }
                AssetDatabase.StopAssetEditing();

                // == 5. ==

                // Create new baked state array
                var targetSize        = m_HDProbeBakedStates.Length + addCount - remCount;
                var targetBakedStates = stackalloc HDProbeBakedState[targetSize];
                // Copy baked state that are not removed
                var targetI = 0;
                for (int i = 0; i < m_HDProbeBakedStates.Length; ++i)
                {
                    if (CoreUnsafeUtils.IndexOf(remIndices, remCount, i) != -1)
                    {
                        continue;
                    }
                    targetBakedStates[targetI++] = m_HDProbeBakedStates[i];
                }
                // Add new baked states
                for (int i = 0; i < addCount; ++i)
                {
                    var state = states[addIndices[i]];
                    targetBakedStates[targetI++] = new HDProbeBakedState
                    {
                        instanceID     = state.instanceID,
                        probeBakedHash = state.probeBakingHash
                    };
                }
                CoreUnsafeUtils.QuickSort <HDProbeBakedState, Hash128, HDProbeBakedState.ProbeBakedHash>(
                    targetI, targetBakedStates
                    );

                Array.Resize(ref m_HDProbeBakedStates, targetSize);
                if (targetSize > 0)
                {
                    fixed(HDProbeBakedState *bakedStates = &m_HDProbeBakedStates[0])
                    {
                        UnsafeUtility.MemCpy(
                            bakedStates,
                            targetBakedStates,
                            sizeof(HDProbeBakedState) * targetSize
                            );
                    }
                }

                // Update state hash
                Array.Resize(ref m_StateHashes, m_HDProbeBakedStates.Length);
                for (int i = 0; i < m_HDProbeBakedStates.Length; ++i)
                {
                    m_StateHashes[i] = m_HDProbeBakedStates[i].probeBakedHash;
                }
                stateHashes = m_StateHashes;
            }

            handle.ExitStage((int)BakingStages.ReflectionProbes);

            handle.SetIsDone(true);
        }
Ejemplo n.º 17
0
        public override void Tick(
            SceneStateHash sceneStateHash,
            IScriptableBakedReflectionSystemStageNotifier handle
            )
        {
            if (!AreAllOpenedSceneSaved())
            {
                handle.SetIsDone(true);
                return;
            }

            // On the C# side, we don't have non blocking asset import APIs, and we don't want to block the
            //   UI when the user is editing the world.
            //   So, we skip the baking when the user is editing any UI control.
            if (GUIUtility.hotControl != 0)
            {
                return;
            }

            if (!IsCurrentSRPValid(out HDRenderPipeline hdPipeline))
            {
                if (ShouldIssueWarningForCurrentSRP())
                {
                    Debug.LogWarning("HDBakedReflectionSystem work with HDRP, " +
                                     "Either switch your render pipeline or use a different reflection system. You may need to trigger a " +
                                     "C# domain reload to initialize the appropriate reflection system. One way to do this is to compile a script.");
                }

                handle.ExitStage((int)BakingStages.ReflectionProbes);
                handle.SetIsDone(true);
                return;
            }

            var ambientProbeHash = sceneStateHash.ambientProbeHash;
            var sceneObjectsHash = sceneStateHash.sceneObjectsHash;
            var skySettingsHash  = sceneStateHash.skySettingsHash;

            DeleteCubemapAssets(true);

            // Explanation of the algorithm:
            // 1. First we create the hash of the world that can impact the reflection probes.
            // 2. Then for each probe, we calculate a hash that represent what this specific probe should have baked.
            // 3. We compare those hashes against the baked one and decide:
            //   a. If we have to remove a baked data
            //   b. If we have to bake a probe
            // 4. Bake all required probes
            //   a. Bake probe that were added or modified
            //   b. Bake probe with a missing baked texture
            // 5. Remove unused baked data
            // 6. Update probe assets

            // == 1. ==
            var allProbeDependencyHash = new Hash128();

            // TODO: All baked probes depend on custom probes (hash all custom probes and set as dependency)
            // TODO: All baked probes depend on HDRP specific Light settings
            HashUtilities.AppendHash(ref ambientProbeHash, ref allProbeDependencyHash);
            HashUtilities.AppendHash(ref sceneObjectsHash, ref allProbeDependencyHash);
            HashUtilities.AppendHash(ref skySettingsHash, ref allProbeDependencyHash);

            var bakedProbes     = HDProbeSystem.bakedProbes;
            var bakedProbeCount = HDProbeSystem.bakedProbeCount;

            // == 2. ==
            var states = stackalloc HDProbeBakingState[bakedProbeCount];
            // A list of indices of probe we may want to force to rebake, even if the hashes matches.
            // Usually, add a probe when something external to its state or the world state forces the bake.
            var probeForcedToBakeIndices      = stackalloc int[bakedProbeCount];
            var probeForcedToBakeIndicesCount = 0;
            var probeForcedToBakeIndicesList  = new ListBuffer <int>(
                probeForcedToBakeIndices,
                &probeForcedToBakeIndicesCount,
                bakedProbeCount
                );

            ComputeProbeInstanceID(bakedProbes, states);
            ComputeProbeSettingsHashes(bakedProbes, states);
            // TODO: Handle bounce dependency here
            ComputeProbeBakingHashes(bakedProbeCount, allProbeDependencyHash, states);

            // Force to rebake probe with missing baked texture
            for (var i = 0; i < bakedProbeCount; ++i)
            {
                var instanceId = states[i].instanceID;
                var probe      = (HDProbe)EditorUtility.InstanceIDToObject(instanceId);
                if (probe.bakedTexture != null && !probe.bakedTexture.Equals(null))
                {
                    continue;
                }

                probeForcedToBakeIndicesList.TryAdd(i);
            }

            CoreUnsafeUtils.QuickSort <HDProbeBakingState, Hash128, HDProbeBakingState.ProbeBakingHash>(
                bakedProbeCount, states
                );

            int operationCount = 0, addCount = 0, remCount = 0;
            var maxProbeCount = Mathf.Max(bakedProbeCount, m_HDProbeBakedStates.Length);
            var addIndices    = stackalloc int[maxProbeCount];
            var remIndices    = stackalloc int[maxProbeCount];

            if (m_HDProbeBakedStates.Length == 0)
            {
                for (int i = 0; i < bakedProbeCount; ++i)
                {
                    addIndices[addCount++] = i;
                }
                operationCount = addCount;
            }
            else
            {
                fixed(HDProbeBakedState *oldBakedStates = &m_HDProbeBakedStates[0])
                {
                    // == 3. ==
                    // Compare hashes between baked probe states and desired probe states
                    operationCount = CoreUnsafeUtils.CompareHashes <
                        HDProbeBakedState, HDProbeBakedState.ProbeBakedHash,
                        HDProbeBakingState, HDProbeBakingState.ProbeBakingHash
                        > (
                        m_HDProbeBakedStates.Length, oldBakedStates, // old hashes
                        bakedProbeCount, states,                     // new hashes
                        addIndices, remIndices,
                        out addCount, out remCount
                        );
                }
            }

            if (operationCount > 0 || probeForcedToBakeIndicesList.Count > 0)
            {
                // == 4. ==
                var cubemapSize = (int)hdPipeline.currentPlatformRenderPipelineSettings.lightLoopSettings.reflectionCubemapSize;
                // We force RGBAHalf as we don't support 11-11-10 textures (only RT)
                var probeFormat = GraphicsFormat.R16G16B16A16_SFloat;

                var cubeRT = HDRenderUtilities.CreateReflectionProbeRenderTarget(cubemapSize, probeFormat);

                handle.EnterStage(
                    (int)BakingStages.ReflectionProbes,
                    string.Format("Reflection Probes | {0} jobs", addCount),
                    0
                    );

                // Compute indices of probes to bake: added, modified probe or with a missing baked texture.
                var toBakeIndices      = stackalloc int[bakedProbeCount];
                var toBakeIndicesCount = 0;
                var toBakeIndicesList  = new ListBuffer <int>(toBakeIndices, &toBakeIndicesCount, bakedProbeCount);
                {
                    // Note: we will add probes from change check and baked texture missing check.
                    //   So we can add at most 2 time the probe in the list.
                    var toBakeIndicesTmp      = stackalloc int[bakedProbeCount * 2];
                    var toBakeIndicesTmpCount = 0;
                    var toBakeIndicesTmpList  =
                        new ListBuffer <int>(toBakeIndicesTmp, &toBakeIndicesTmpCount, bakedProbeCount * 2);

                    // Add the indices from the added or modified detection check
                    toBakeIndicesTmpList.TryCopyFrom(addIndices, addCount);
                    // Add the probe with missing baked texture check
                    probeForcedToBakeIndicesList.TryCopyTo(toBakeIndicesTmpList);

                    // Sort indices
                    toBakeIndicesTmpList.QuickSort();
                    // Add to final list without the duplicates
                    var lastValue = int.MaxValue;
                    for (var i = 0; i < toBakeIndicesTmpList.Count; ++i)
                    {
                        if (lastValue == toBakeIndicesTmpList.GetUnchecked(i))
                        {
                            // Skip duplicates
                            continue;
                        }

                        lastValue = toBakeIndicesTmpList.GetUnchecked(i);
                        toBakeIndicesList.TryAdd(lastValue);
                    }
                }

                // Render probes that were added or modified
                for (int i = 0; i < toBakeIndicesList.Count; ++i)
                {
                    handle.EnterStage(
                        (int)BakingStages.ReflectionProbes,
                        string.Format("Reflection Probes | {0} jobs", addCount),
                        i / (float)toBakeIndicesCount
                        );

                    var index      = toBakeIndicesList.GetUnchecked(i);
                    var instanceId = states[index].instanceID;
                    var probe      = (HDProbe)EditorUtility.InstanceIDToObject(instanceId);
                    var cacheFile  = GetGICacheFileForHDProbe(states[index].probeBakingHash);

                    // Get from cache or render the probe
                    if (!File.Exists(cacheFile))
                    {
                        var planarRT = HDRenderUtilities.CreatePlanarProbeRenderTarget((int)probe.resolution, probeFormat);
                        RenderAndWriteToFile(probe, cacheFile, cubeRT, planarRT);
                        planarRT.Release();
                    }
                }
                cubeRT.Release();

                // Copy texture from cache
                for (int i = 0; i < toBakeIndicesList.Count; ++i)
                {
                    var index      = toBakeIndicesList.GetUnchecked(i);
                    var instanceId = states[index].instanceID;
                    var probe      = (HDProbe)EditorUtility.InstanceIDToObject(instanceId);
                    var cacheFile  = GetGICacheFileForHDProbe(states[index].probeBakingHash);

                    if (string.IsNullOrEmpty(probe.gameObject.scene.path))
                    {
                        continue;
                    }

                    Assert.IsTrue(File.Exists(cacheFile));

                    var bakedTexturePath = HDBakingUtilities.GetBakedTextureFilePath(probe);
                    HDBakingUtilities.CreateParentDirectoryIfMissing(bakedTexturePath);
                    Checkout(bakedTexturePath);
                    // Checkout will make those file writeable, but this is not immediate,
                    // so we retries when this fails.
                    if (!HDEditorUtils.CopyFileWithRetryOnUnauthorizedAccess(cacheFile, bakedTexturePath))
                    {
                        return;
                    }
                }
                // AssetPipeline bug
                // Sometimes, the baked texture reference is destroyed during 'AssetDatabase.StopAssetEditing()'
                //   thus, the reference to the baked texture in the probe is lost
                // Although, importing twice the texture seems to workaround the issue
                for (int j = 0; j < 2; ++j)
                {
                    AssetDatabase.StartAssetEditing();
                    for (int i = 0; i < bakedProbeCount; ++i)
                    {
                        var index      = toBakeIndicesList.GetUnchecked(i);
                        var instanceId = states[index].instanceID;
                        var probe      = (HDProbe)EditorUtility.InstanceIDToObject(instanceId);
                        if (string.IsNullOrEmpty(probe.gameObject.scene.path))
                        {
                            continue;
                        }

                        var bakedTexturePath = HDBakingUtilities.GetBakedTextureFilePath(probe);
                        AssetDatabase.ImportAsset(bakedTexturePath);
                        ImportAssetAt(probe, bakedTexturePath);
                    }
                    AssetDatabase.StopAssetEditing();
                }
                // Import assets
                AssetDatabase.StartAssetEditing();
                for (int i = 0; i < toBakeIndicesList.Count; ++i)
                {
                    var index      = toBakeIndicesList.GetUnchecked(i);
                    var instanceId = states[index].instanceID;
                    var probe      = (HDProbe)EditorUtility.InstanceIDToObject(instanceId);
                    if (string.IsNullOrEmpty(probe.gameObject.scene.path))
                    {
                        continue;
                    }

                    var bakedTexturePath = HDBakingUtilities.GetBakedTextureFilePath(probe);
                    var bakedTexture     = AssetDatabase.LoadAssetAtPath <Texture>(bakedTexturePath);
                    Assert.IsNotNull(bakedTexture, "The baked texture was imported before, " +
                                     "so it must exists in AssetDatabase");

                    probe.SetTexture(ProbeSettings.Mode.Baked, bakedTexture);
                    EditorUtility.SetDirty(probe);
                }
                AssetDatabase.StopAssetEditing();

                // == 5. ==

                // Create new baked state array
                var targetSize        = m_HDProbeBakedStates.Length - remCount + toBakeIndicesList.Count;
                var targetBakedStates = stackalloc HDProbeBakedState[targetSize];
                // Copy baked state that are not removed
                var targetI = 0;
                for (int i = 0; i < m_HDProbeBakedStates.Length; ++i)
                {
                    if (CoreUnsafeUtils.IndexOf(remIndices, remCount, i) != -1)
                    {
                        continue;
                    }
                    Assert.IsTrue(targetI < targetSize);
                    targetBakedStates[targetI++] = m_HDProbeBakedStates[i];
                }
                // Add new baked states
                for (int i = 0; i < toBakeIndicesList.Count; ++i)
                {
                    var state = states[toBakeIndicesList.GetUnchecked(i)];
                    Assert.IsTrue(targetI < targetSize);
                    targetBakedStates[targetI++] = new HDProbeBakedState
                    {
                        instanceID     = state.instanceID,
                        probeBakedHash = state.probeBakingHash
                    };
                }
                CoreUnsafeUtils.QuickSort <HDProbeBakedState, Hash128, HDProbeBakedState.ProbeBakedHash>(
                    targetI, targetBakedStates
                    );

                Array.Resize(ref m_HDProbeBakedStates, targetSize);
                if (targetSize > 0)
                {
                    fixed(HDProbeBakedState *bakedStates = &m_HDProbeBakedStates[0])
                    {
                        UnsafeUtility.MemCpy(
                            bakedStates,
                            targetBakedStates,
                            sizeof(HDProbeBakedState) * targetSize
                            );
                    }
                }

                // Update state hash
                Array.Resize(ref m_StateHashes, m_HDProbeBakedStates.Length);
                for (int i = 0; i < m_HDProbeBakedStates.Length; ++i)
                {
                    m_StateHashes[i] = m_HDProbeBakedStates[i].probeBakedHash;
                }
                stateHashes = m_StateHashes;
            }

            handle.ExitStage((int)BakingStages.ReflectionProbes);

            handle.SetIsDone(true);
        }