/// <summary> /// Synchronize memory for a given texture. /// If overlapping tracking handles are dirty, fully or partially synchronize the texture data. /// </summary> /// <param name="texture">The texture being used</param> public void SynchronizeMemory(Texture texture) { EvaluateRelevantHandles(texture, (baseHandle, regionCount, split) => { bool dirty = false; bool anyModified = false; bool anyUnmapped = false; for (int i = 0; i < regionCount; i++) { TextureGroupHandle group = _handles[baseHandle + i]; bool modified = group.Modified; bool handleDirty = false; bool handleModified = false; bool handleUnmapped = false; foreach (CpuRegionHandle handle in group.Handles) { if (handle.Dirty) { handle.Reprotect(); handleDirty = true; } else { handleUnmapped |= handle.Unmapped; handleModified |= modified; } } // Evaluate if any copy dependencies need to be fulfilled. A few rules: // If the copy handle needs to be synchronized, prefer our own state. // If we need to be synchronized and there is a copy present, prefer the copy. if (group.NeedsCopy && group.Copy()) { anyModified |= true; // The copy target has been modified. handleDirty = false; } else { anyModified |= handleModified; dirty |= handleDirty; } anyUnmapped |= handleUnmapped; if (group.NeedsCopy) { // The texture we copied from is still being written to. Copy from it again the next time this texture is used. texture.SignalGroupDirty(); } _loadNeeded[baseHandle + i] = handleDirty && !handleUnmapped; } if (dirty) { if (anyUnmapped || (_handles.Length > 1 && (anyModified || split))) { // Partial texture invalidation. Only update the layers/levels with dirty flags of the storage. SynchronizePartial(baseHandle, regionCount); } else { // Full texture invalidation. texture.SynchronizeFull(); } } }); }