internal bool Load(bool wait, Func <Texture2D> load) { if (LoadImmediately) { Texture_Unsafe?.Dispose(); Texture_Unsafe = load(); FreeFastTextureLoad(); return(true); } // Let's queue a reload onto the main thread and call it a day. // Make sure to read the texture size immediately though! object queuedLoadLock; lock (queuedLoadLock = new object()) { _Texture_QueuedLoadLock = queuedLoadLock; Func <Texture2D> _load = load; load = () => { Texture2D tex; lock (queuedLoadLock) { if (_Texture_QueuedLoadLock != queuedLoadLock) { _load = null; FreeFastTextureLoad(); return(Texture_Unsafe); } // NOTE: If something dares to change texture info on the fly, GOOD LUCK. Texture_Unsafe?.Dispose(); Texture_Unsafe = tex = _load(); FreeFastTextureLoad(); _Texture_QueuedLoadLock = null; } if (_Texture_UnloadAfterReload) { tex?.Dispose(); tex = Texture_Unsafe; // ... can anything even swap the texture here? Texture_Unsafe = null; tex?.Dispose(); _Texture_UnloadAfterReload = false; } return(tex); }; _Texture_QueuedLoad = !_Texture_FTLLoading? MainThreadHelper.GetForceQueue(load) : MainThreadHelper.Get(load); } if (wait || _Texture_Requesting) { _Texture_QueuedLoad.GetResult(); } return(false); }
private bool ResetVertexBuffer() { // Checking for IsDisposed on other threads should be fine... if (Vertices != null && !Vertices.IsDisposed && !Vertices.GraphicsDevice.IsDisposed) { return(false); } // Handle already queued loads appropriately. object queuedLoadLock = _Vertices_QueuedLoadLock; if (queuedLoadLock != null) { lock (queuedLoadLock) { // Queued task finished just in time. if (_Vertices_QueuedLoadLock == null) { return(true); } // If we still can, cancel the queued load, then proceed with lazy-loading. if (MainThreadHelper.IsMainThread) { _Vertices_QueuedLoadLock = null; } } if (!MainThreadHelper.IsMainThread) { // Otherwise wait for it to get loaded, don't reload twice. (Don't wait locked!) while (!_Vertices_QueuedLoad.IsValid) { Thread.Yield(); } _Vertices_QueuedLoad.GetResult(); return(true); } } if (!(CoreModule.Settings.ThreadedGL ?? Everest.Flags.PreferThreadedGL) && !MainThreadHelper.IsMainThread && queuedLoadLock == null) { // Let's queue a reload onto the main thread and call it a day. lock (queuedLoadLock = new object()) { _Vertices_QueuedLoadLock = queuedLoadLock; _Vertices_QueuedLoad = MainThreadHelper.Get(() => { lock (queuedLoadLock) { if (_Vertices_QueuedLoadLock == null) { return(Vertices); } // Force-reload as we already returned true on the other thread. Vertices?.Dispose(); // NOTE: If something dares to change verts on the fly, make it wait on any existing tasks, then make it force-reload. Vertices = new VertexBuffer(Engine.Graphics.GraphicsDevice, typeof(VertexPositionTexture), verts.Length, BufferUsage.None); Vertices.SetData(verts); _Vertices_QueuedLoadLock = null; return(Vertices); } }); } return(true); } return(orig_ResetVertexBuffer()); }
internal override void Unload() { Texture2D tex = Texture_Unsafe; // Handle already queued loads appropriately. object queuedLoadLock = _Texture_QueuedLoadLock; if (queuedLoadLock != null) { bool gotLock = false; try { Monitor.TryEnter(queuedLoadLock, ref gotLock); if (gotLock) { if (_Texture_QueuedLoadLock != null) { // If we still can, cancel the queued load. _Texture_QueuedLoadLock = null; } } else { // Welp. _Texture_UnloadAfterReload = true; Monitor.TryEnter(queuedLoadLock, ref gotLock); if (gotLock) { // It might be too late - let's unload ourselves. _Texture_UnloadAfterReload = false; } else { // The loader will still handle the request. return; } } } finally { if (gotLock) { Monitor.Exit(queuedLoadLock); } } if (!MainThreadHelper.IsMainThread) { // Otherwise wait for it to get loaded. (Don't wait locked!) while (!_Texture_QueuedLoad.IsValid) { Thread.Yield(); } tex = _Texture_QueuedLoad.GetResult(); } } Texture_Unsafe = null; if (tex == null || tex.IsDisposed) { return; } if (!(CoreModule.Settings.ThreadedGL ?? Everest.Flags.PreferThreadedGL) && !MainThreadHelper.IsMainThread) { MainThreadHelper.Do(() => tex.Dispose()); } else { tex.Dispose(); } }
public new void ResetBillboardBuffers() { // Checking for IsDisposed on other threads should be fine... if (billboardVertices != null && !billboardIndices.IsDisposed && !billboardIndices.GraphicsDevice.IsDisposed && billboardVertices != null && !billboardVertices.IsDisposed && !billboardVertices.GraphicsDevice.IsDisposed && billboardInfo.Length <= billboardVertices.VertexCount) { return; } // Handle already queued loads appropriately. object queuedLoadLock = _Billboard_QueuedLoadLock; if (queuedLoadLock != null) { lock (queuedLoadLock) { // Queued task finished just in time. if (_Billboard_QueuedLoadLock == null) { return; } // If we still can, cancel the queued load, then proceed with lazy-loading. if (MainThreadHelper.IsMainThread) { _Billboard_QueuedLoadLock = null; } } if (!MainThreadHelper.IsMainThread) { // Otherwise wait for it to get loaded, don't reload twice. (Don't wait locked!) while (!_Billboard_QueuedLoad.IsValid) { Thread.Yield(); } _Billboard_QueuedLoad.GetResult(); return; } } if (!(CoreModule.Settings.ThreadedGL ?? Everest.Flags.PreferThreadedGL) && !MainThreadHelper.IsMainThread && queuedLoadLock == null) { // Let's queue a reload onto the main thread and call it a day. lock (queuedLoadLock = new object()) { _Billboard_QueuedLoadLock = queuedLoadLock; _Billboard_QueuedLoad = MainThreadHelper.Get(() => { lock (queuedLoadLock) { if (_Billboard_QueuedLoadLock == null) { return(billboardVertices); } // Force-reload as we already returned true on the other thread. if (billboardVertices != null && !billboardVertices.IsDisposed) { billboardVertices.Dispose(); } if (billboardIndices != null && !billboardIndices.IsDisposed) { billboardIndices.Dispose(); } // NOTE: If something dares to change verts on the fly, make it wait on any existing tasks, then make it force-reload. // Let's rely on the original code for now. orig_ResetBillboardBuffers(); _Billboard_QueuedLoadLock = null; return(billboardVertices); } }); } return; } orig_ResetBillboardBuffers(); }