示例#1
0
        internal override unsafe void Reload()
        {
            // Unload task might end up conflicting with Reload - let's instead force-unload in Load.
            // Unload();

            // Handle already queued loads appropriately.
            object queuedLoadLock = _Texture_QueuedLoadLock;

            if (queuedLoadLock != null && !_Texture_Reloading)
            {
                lock (queuedLoadLock) {
                    // Queued task finished just in time.
                    if (_Texture_QueuedLoadLock != queuedLoadLock)
                    {
                        return;
                    }

                    // If we still can, cancel the queued load, then proceed with lazy-loading.
                    if (MainThreadHelper.IsMainThread)
                    {
                        _Texture_QueuedLoadLock = null;
                    }
                }

                if (!MainThreadHelper.IsMainThread)
                {
                    // Otherwise wait for it to get loaded, don't reload twice. (Don't wait locked!)
                    while (!_Texture_QueuedLoad.IsValid)
                    {
                        Thread.Yield();
                    }
                    _Texture_QueuedLoad.GetResult();
                    return;
                }
            }

            if (ftlEnabled && CanPreload && (Metadata?.StreamAsync ?? true) &&
                !_Texture_Reloading && !_Texture_Requesting)
            {
                // Preload as we need to know the texture size WITHOUT ALLOCATING SPACE.
                // ... also because the texture size is required in the calling ctx past Reload.
                if (Preload(true))
                {
                    CountFastTextureLoad();
                    lock (queuedLoadLock = new object()) {
                        _Texture_QueuedLoadLock = queuedLoadLock;
                        _Texture_QueuedLoad     = new MaybeAwaitable <Texture2D>(Task.Run(() => {
                            try {
                                lock (queuedLoadLock) {
                                    // Queued load cancelled or replaced with another queued load.
                                    if (_Texture_QueuedLoadLock != queuedLoadLock)
                                    {
                                        FreeFastTextureLoad();
                                        return(Texture_Unsafe);
                                    }

                                    GrabFastTextureLoad();

                                    // NOTE: If something dares to change texture info on the fly, GOOD LUCK.
                                    _Texture_Reloading = true;
                                    Reload();
                                    if (_Texture_QueuedLoadLock == queuedLoadLock)
                                    {
                                        _Texture_QueuedLoadLock = null;
                                    }
                                    Texture2D tex = Texture_Unsafe;
                                    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);
                                }
                            } catch (Exception e) {
                                Celeste.patch_Celeste.CriticalFailureHandler(e);
                                throw;
                            }
                        }).GetAwaiter());
                        return;
                    }
                }
            }

            _Texture_Reloading = false;

            if (Metadata != null)
            {
                if (Metadata.StreamAsync || MainThreadHelper.IsMainThread)
                {
                    Stream stream = Metadata.Stream;
                    if (stream != null)
                    {
                        using (stream) {
                            bool premul = false; // Assume unpremultiplied by default.
                            if (Metadata.TryGetMeta(out TextureMeta meta))
                            {
                                premul = meta.Premultiplied;
                            }

                            if (ContentExtensions.TextureSetDataSupportsPtr)
                            {
                                int    w, h;
                                IntPtr dataPtr;
                                if (premul)
                                {
                                    ContentExtensions.LoadTextureRaw(Celeste.Celeste.Instance.GraphicsDevice, stream, out w, out h, out dataPtr);
                                }
                                else
                                {
                                    ContentExtensions.LoadTextureLazyPremultiply(Celeste.Celeste.Instance.GraphicsDevice, stream, out w, out h, out dataPtr);
                                }
                                stream.Dispose();
                                Width  = w;
                                Height = h;
                                Load(false, () => {
                                    Texture2D tex = new Texture2D(Celeste.Celeste.Instance.GraphicsDevice, w, h, false, SurfaceFormat.Color);
                                    tex.SetData(dataPtr);
                                    ContentExtensions.UnloadTextureRaw(dataPtr);
                                    return(tex);
                                });
                            }
                            else
                            {
                                int    w, h;
                                byte[] data;
                                if (premul)
                                {
                                    ContentExtensions.LoadTextureRaw(Celeste.Celeste.Instance.GraphicsDevice, stream, out w, out h, out data);
                                }
                                else
                                {
                                    ContentExtensions.LoadTextureLazyPremultiply(Celeste.Celeste.Instance.GraphicsDevice, stream, out w, out h, out data);
                                }
                                stream.Dispose();
                                Width  = w;
                                Height = h;
                                Load(false, () => {
                                    Texture2D tex = new Texture2D(Celeste.Celeste.Instance.GraphicsDevice, w, h, false, SurfaceFormat.Color);
                                    tex.SetData(data);
                                    data = null;
                                    return(tex);
                                });
                            }
                        }
                    }
                    else if (Fallback != null)
                    {
                        ((patch_VirtualTexture)(object)Fallback).Reload();
                        Texture_Unsafe = Fallback.Texture;
                    }
                }
                else
                {
                    // This is ugly but if the asset doesn't like multithreading, so be it.
                    // Not even preloading will be beneficial here, and forget about GetMeta.
                    Load(true, () => {
                        using (Stream stream = Metadata.Stream) {
                            if (stream != null)
                            {
                                bool premul = false; // Assume unpremultiplied by default.
                                if (Metadata.TryGetMeta(out TextureMeta meta))
                                {
                                    premul = meta.Premultiplied;
                                }

                                if (premul)
                                {
                                    Texture2D tex = Texture2D.FromStream(Celeste.Celeste.Instance.GraphicsDevice, stream);
                                    return(tex);
                                }
                                else if (ContentExtensions.TextureSetDataSupportsPtr)
                                {
                                    ContentExtensions.LoadTextureLazyPremultiply(Celeste.Celeste.Instance.GraphicsDevice, stream, out int w, out int h, out IntPtr dataPtr);
                                    Texture2D tex = new Texture2D(Celeste.Celeste.Instance.GraphicsDevice, w, h, false, SurfaceFormat.Color);
                                    tex.SetData(dataPtr);
                                    ContentExtensions.UnloadTextureRaw(dataPtr);
                                    return(tex);
                                }
                                else
                                {
                                    ContentExtensions.LoadTextureLazyPremultiply(Celeste.Celeste.Instance.GraphicsDevice, stream, out int w, out int h, out byte[] data);
                                    Texture2D tex = new Texture2D(Celeste.Celeste.Instance.GraphicsDevice, w, h, false, SurfaceFormat.Color);
                                    tex.SetData(data);
                                    data = null;
                                    return(tex);
                                }
                            }
                            else if (Fallback != null)
                            {
                                ((patch_VirtualTexture)(object)Fallback).Reload();
                                return(Fallback.Texture);
                            }

                            return(null);
                        }