From 16d88c21fc98cd7302811e142a39d590370e182e Mon Sep 17 00:00:00 2001 From: gdk Date: Sat, 23 Nov 2019 23:24:03 -0300 Subject: [PATCH] Improved and simplified window texture presentation --- Ryujinx.Graphics.GAL/IWindow.cs | 6 +- Ryujinx.Graphics.Gpu/Engine/Methods.cs | 2 - Ryujinx.Graphics.Gpu/GpuContext.cs | 38 +--- Ryujinx.Graphics.Gpu/Image/Texture.cs | 12 - Ryujinx.Graphics.Gpu/Image/TextureManager.cs | 26 +-- .../Memory/ConcurrentRangeList.cs | 208 ------------------ Ryujinx.Graphics.Gpu/Window.cs | 94 ++++++++ Ryujinx.Graphics.OpenGL/Window.cs | 196 +---------------- .../HOS/Services/SurfaceFlinger/NvFlinger.cs | 43 ++-- Ryujinx.HLE/Switch.cs | 5 + Ryujinx/Ui/GLScreen.cs | 4 +- 11 files changed, 137 insertions(+), 497 deletions(-) delete mode 100644 Ryujinx.Graphics.Gpu/Memory/ConcurrentRangeList.cs create mode 100644 Ryujinx.Graphics.Gpu/Window.cs diff --git a/Ryujinx.Graphics.GAL/IWindow.cs b/Ryujinx.Graphics.GAL/IWindow.cs index 3d5130c2..369f7b9a 100644 --- a/Ryujinx.Graphics.GAL/IWindow.cs +++ b/Ryujinx.Graphics.GAL/IWindow.cs @@ -2,11 +2,7 @@ namespace Ryujinx.Graphics.GAL { public interface IWindow { - void Present(); - - void QueueTexture(ITexture texture, ImageCrop crop, object context); - - void RegisterTextureReleaseCallback(TextureReleaseCallback callback); + void Present(ITexture texture, ImageCrop crop); void SetSize(int width, int height); } diff --git a/Ryujinx.Graphics.Gpu/Engine/Methods.cs b/Ryujinx.Graphics.Gpu/Engine/Methods.cs index 1832a5e3..19e67993 100644 --- a/Ryujinx.Graphics.Gpu/Engine/Methods.cs +++ b/Ryujinx.Graphics.Gpu/Engine/Methods.cs @@ -76,8 +76,6 @@ namespace Ryujinx.Graphics.Gpu.Engine state.RegisterCallback(MethodOffset.UniformBufferBindFragment, UniformBufferBindFragment); } - public Image.Texture GetTexture(ulong address) => _textureManager.Find2(address); - private void UpdateState(GpuState state) { // Shaders must be the first one to be updated if modified, because diff --git a/Ryujinx.Graphics.Gpu/GpuContext.cs b/Ryujinx.Graphics.Gpu/GpuContext.cs index b52e4e49..51961522 100644 --- a/Ryujinx.Graphics.Gpu/GpuContext.cs +++ b/Ryujinx.Graphics.Gpu/GpuContext.cs @@ -1,9 +1,6 @@ using Ryujinx.Graphics.GAL; -using Ryujinx.Graphics.GAL.Texture; using Ryujinx.Graphics.Gpu.Engine; -using Ryujinx.Graphics.Gpu.Image; using Ryujinx.Graphics.Gpu.Memory; -using Ryujinx.Graphics.Gpu.State; using System; namespace Ryujinx.Graphics.Gpu @@ -24,6 +21,8 @@ namespace Ryujinx.Graphics.Gpu public DmaPusher DmaPusher { get; } + public Window Window { get; } + internal int SequenceNumber { get; private set; } private Lazy _caps; @@ -44,6 +43,8 @@ namespace Ryujinx.Graphics.Gpu DmaPusher = new DmaPusher(this); + Window = new Window(this); + _caps = new Lazy(GetCapabilities); } @@ -52,37 +53,6 @@ namespace Ryujinx.Graphics.Gpu SequenceNumber++; } - public ITexture GetTexture( - ulong address, - int width, - int height, - int stride, - bool isLinear, - int gobBlocksInY, - Format format, - int bytesPerPixel) - { - FormatInfo formatInfo = new FormatInfo(format, 1, 1, bytesPerPixel); - - TextureInfo info = new TextureInfo( - address, - width, - height, - 1, - 1, - 1, - 1, - stride, - isLinear, - gobBlocksInY, - 1, - 1, - Target.Texture2D, - formatInfo); - - return Methods.GetTexture(address)?.HostTexture; - } - private Capabilities GetCapabilities() { return Renderer.GetCapabilities(); diff --git a/Ryujinx.Graphics.Gpu/Image/Texture.cs b/Ryujinx.Graphics.Gpu/Image/Texture.cs index 28ad3f77..120abe3f 100644 --- a/Ryujinx.Graphics.Gpu/Image/Texture.cs +++ b/Ryujinx.Graphics.Gpu/Image/Texture.cs @@ -335,18 +335,6 @@ namespace Ryujinx.Graphics.Gpu.Image return true; } - if (_info.FormatInfo.Format == Format.R8G8B8A8Srgb && - info.FormatInfo.Format == Format.R8G8B8A8Unorm && !strict) - { - return true; - } - - if (_info.FormatInfo.Format == Format.R8G8B8A8Unorm && - info.FormatInfo.Format == Format.R8G8B8A8Srgb && !strict) - { - return true; - } - return _info.FormatInfo.Format == info.FormatInfo.Format; } diff --git a/Ryujinx.Graphics.Gpu/Image/TextureManager.cs b/Ryujinx.Graphics.Gpu/Image/TextureManager.cs index 045c2ed9..413ba327 100644 --- a/Ryujinx.Graphics.Gpu/Image/TextureManager.cs +++ b/Ryujinx.Graphics.Gpu/Image/TextureManager.cs @@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Image private ITexture[] _rtHostColors; private ITexture _rtHostDs; - private ConcurrentRangeList _textures; + private RangeList _textures; private AutoDeleteCache _cache; @@ -39,7 +39,7 @@ namespace Ryujinx.Graphics.Gpu.Image _rtHostColors = new ITexture[Constants.TotalRenderTargets]; - _textures = new ConcurrentRangeList(); + _textures = new RangeList(); _cache = new AutoDeleteCache(); } @@ -561,28 +561,6 @@ namespace Ryujinx.Graphics.Gpu.Image info.SwizzleA); } - public Texture Find2(ulong address) - { - Texture[] ts = _textures.FindOverlaps(address, 1); - - if (ts.Length == 2) - { - return ts[1]; - } - - if (ts.Length == 0) - { - ts = _textures.FindOverlaps(address - 1, 2); - } - - if (ts.Length == 0) - { - return null; - } - - return ts[0]; - } - public void Flush() { foreach (Texture texture in _cache) diff --git a/Ryujinx.Graphics.Gpu/Memory/ConcurrentRangeList.cs b/Ryujinx.Graphics.Gpu/Memory/ConcurrentRangeList.cs deleted file mode 100644 index 6d7d1ce2..00000000 --- a/Ryujinx.Graphics.Gpu/Memory/ConcurrentRangeList.cs +++ /dev/null @@ -1,208 +0,0 @@ -using System.Collections.Generic; - -namespace Ryujinx.Graphics.Gpu.Memory -{ - class ConcurrentRangeList where T : IRange - { - private List _items; - - public ConcurrentRangeList() - { - _items = new List(); - } - - public void Add(T item) - { - lock (_items) - { - int index = BinarySearch(item.Address); - - if (index < 0) - { - index = ~index; - } - - _items.Insert(index, item); - } - } - - public bool Remove(T item) - { - lock (_items) - { - int index = BinarySearch(item.Address); - - if (index >= 0) - { - while (index > 0 && _items[index - 1].Address == item.Address) - { - index--; - } - - while (index < _items.Count) - { - if (_items[index].Equals(item)) - { - _items.RemoveAt(index); - - return true; - } - - if (_items[index].Address > item.Address) - { - break; - } - - index++; - } - } - } - - return false; - } - - public T FindFirstOverlap(T item) - { - return FindFirstOverlap(item.Address, item.Size); - } - - public T FindFirstOverlap(ulong address, ulong size) - { - lock (_items) - { - int index = BinarySearch(address, size); - - if (index < 0) - { - return default(T); - } - - return _items[index]; - } - } - - public T[] FindOverlaps(T item) - { - return FindOverlaps(item.Address, item.Size); - } - - public T[] FindOverlaps(ulong address, ulong size) - { - List overlapsList = new List(); - - ulong endAddress = address + size; - - lock (_items) - { - foreach (T item in _items) - { - if (item.Address >= endAddress) - { - break; - } - - if (item.OverlapsWith(address, size)) - { - overlapsList.Add(item); - } - } - } - - return overlapsList.ToArray(); - } - - public T[] FindOverlaps(ulong address) - { - List overlapsList = new List(); - - lock (_items) - { - int index = BinarySearch(address); - - if (index >= 0) - { - while (index > 0 && _items[index - 1].Address == address) - { - index--; - } - - while (index < _items.Count) - { - T overlap = _items[index++]; - - if (overlap.Address != address) - { - break; - } - - overlapsList.Add(overlap); - } - } - } - - return overlapsList.ToArray(); - } - - private int BinarySearch(ulong address) - { - int left = 0; - int right = _items.Count - 1; - - while (left <= right) - { - int range = right - left; - - int middle = left + (range >> 1); - - T item = _items[middle]; - - if (item.Address == address) - { - return middle; - } - - if (address < item.Address) - { - right = middle - 1; - } - else - { - left = middle + 1; - } - } - - return ~left; - } - - private int BinarySearch(ulong address, ulong size) - { - int left = 0; - int right = _items.Count - 1; - - while (left <= right) - { - int range = right - left; - - int middle = left + (range >> 1); - - T item = _items[middle]; - - if (item.OverlapsWith(address, size)) - { - return middle; - } - - if (address < item.Address) - { - right = middle - 1; - } - else - { - left = middle + 1; - } - } - - return ~left; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Graphics.Gpu/Window.cs b/Ryujinx.Graphics.Gpu/Window.cs new file mode 100644 index 00000000..a3dc3b26 --- /dev/null +++ b/Ryujinx.Graphics.Gpu/Window.cs @@ -0,0 +1,94 @@ +using Ryujinx.Graphics.GAL; +using Ryujinx.Graphics.GAL.Texture; +using Ryujinx.Graphics.Gpu.Image; +using System; +using System.Collections.Concurrent; + +namespace Ryujinx.Graphics.Gpu +{ + public class Window + { + private GpuContext _context; + + private struct PresentationTexture + { + public TextureInfo Info { get; } + public ImageCrop Crop { get; } + public Action Callback { get; } + public object UserObj { get; } + + public PresentationTexture( + TextureInfo info, + ImageCrop crop, + Action callback, + object userObj) + { + Info = info; + Crop = crop; + Callback = callback; + UserObj = userObj; + } + } + + private ConcurrentQueue _frameQueue; + + public Window(GpuContext context) + { + _context = context; + + _frameQueue = new ConcurrentQueue(); + } + + public void EnqueueFrameThreadSafe( + ulong address, + int width, + int height, + int stride, + bool isLinear, + int gobBlocksInY, + Format format, + int bytesPerPixel, + ImageCrop crop, + Action callback, + object userObj) + { + FormatInfo formatInfo = new FormatInfo(format, 1, 1, bytesPerPixel); + + TextureInfo info = new TextureInfo( + address, + width, + height, + 1, + 1, + 1, + 1, + stride, + isLinear, + gobBlocksInY, + 1, + 1, + Target.Texture2D, + formatInfo); + + _frameQueue.Enqueue(new PresentationTexture(info, crop, callback, userObj)); + } + + public void Present(Action swapBuffersCallback) + { + _context.AdvanceSequence(); + + if (_frameQueue.TryDequeue(out PresentationTexture pt)) + { + Image.Texture texture = _context.Methods.TextureManager.FindOrCreateTexture(pt.Info); + + texture.SynchronizeMemory(); + + _context.Renderer.Window.Present(texture.HostTexture, pt.Crop); + + swapBuffersCallback(); + + pt.Callback(pt.UserObj); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics.OpenGL/Window.cs b/Ryujinx.Graphics.OpenGL/Window.cs index 3fe83dd1..cf520ed4 100644 --- a/Ryujinx.Graphics.OpenGL/Window.cs +++ b/Ryujinx.Graphics.OpenGL/Window.cs @@ -1,7 +1,6 @@ using OpenTK.Graphics.OpenGL; using Ryujinx.Graphics.GAL; using System; -using System.Collections.Generic; namespace Ryujinx.Graphics.OpenGL { @@ -13,53 +12,19 @@ namespace Ryujinx.Graphics.OpenGL private int _width; private int _height; - private int _resizeWidth; - private int _resizeHeight; - - private bool _sizeChanged; - - private object _resizeLocker; - - private int _blitFramebufferHandle; private int _copyFramebufferHandle; - private int _screenTextureHandle; - - private TextureReleaseCallback _release; - - private struct PresentationTexture - { - public TextureView Texture { get; } - - public ImageCrop Crop { get; } - - public object Context { get; } - - public PresentationTexture(TextureView texture, ImageCrop crop, object context) - { - Texture = texture; - Crop = crop; - Context = context; - } - } - - private Queue _textures; - public Window() { _width = NativeWidth; _height = NativeHeight; - - _resizeLocker = new object(); - - _textures = new Queue(); } - public void Present() + public void Present(ITexture texture, ImageCrop crop) { - GL.Disable(EnableCap.FramebufferSrgb); + TextureView view = (TextureView)texture; - CopyTextureFromQueue(); + GL.Disable(EnableCap.FramebufferSrgb); int oldReadFramebufferHandle = GL.GetInteger(GetPName.ReadFramebufferBinding); int oldDrawFramebufferHandle = GL.GetInteger(GetPName.DrawFramebufferBinding); @@ -67,52 +32,10 @@ namespace Ryujinx.Graphics.OpenGL GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, 0); GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, GetCopyFramebufferHandleLazy()); - GL.ReadBuffer(ReadBufferMode.ColorAttachment0); - - GL.Clear(ClearBufferMask.ColorBufferBit); - - int windowWidth = _width; - int windowHeight = _height; - - GL.BlitFramebuffer( - 0, - 0, - windowWidth, - windowHeight, - 0, - 0, - windowWidth, - windowHeight, - ClearBufferMask.ColorBufferBit, - BlitFramebufferFilter.Linear); - - GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, oldReadFramebufferHandle); - GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, oldDrawFramebufferHandle); - - GL.Enable(EnableCap.FramebufferSrgb); - } - - private void CopyTextureFromQueue() - { - if (!_textures.TryDequeue(out PresentationTexture presentationTexture)) - { - return; - } - - TextureView texture = presentationTexture.Texture; - ImageCrop crop = presentationTexture.Crop; - object context = presentationTexture.Context; - - int oldReadFramebufferHandle = GL.GetInteger(GetPName.ReadFramebufferBinding); - int oldDrawFramebufferHandle = GL.GetInteger(GetPName.DrawFramebufferBinding); - - GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, GetCopyFramebufferHandleLazy()); - GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, GetBlitFramebufferHandleLazy()); - GL.FramebufferTexture( FramebufferTarget.ReadFramebuffer, FramebufferAttachment.ColorAttachment0, - texture.Handle, + view.Handle, 0); GL.ReadBuffer(ReadBufferMode.ColorAttachment0); @@ -124,7 +47,7 @@ namespace Ryujinx.Graphics.OpenGL if (crop.Left == 0 && crop.Right == 0) { srcX0 = 0; - srcX1 = texture.Width; + srcX1 = view.Width; } else { @@ -135,7 +58,7 @@ namespace Ryujinx.Graphics.OpenGL if (crop.Top == 0 && crop.Bottom == 0) { srcY0 = 0; - srcY1 = texture.Height; + srcY1 = view.Height; } else { @@ -173,126 +96,25 @@ namespace Ryujinx.Graphics.OpenGL GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, oldReadFramebufferHandle); GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, oldDrawFramebufferHandle); - texture.Release(); - - Release(context); - } - - public void QueueTexture(ITexture texture, ImageCrop crop, object context) - { - if (texture == null) - { - Release(context); - - return; - } - - TextureView textureView = (TextureView)texture; - - textureView.Acquire(); - - _textures.Enqueue(new PresentationTexture(textureView, crop, context)); - } - - public void RegisterTextureReleaseCallback(TextureReleaseCallback callback) - { - _release = callback; + GL.Enable(EnableCap.FramebufferSrgb); } public void SetSize(int width, int height) { - lock (_resizeLocker) - { - _resizeWidth = width; - _resizeHeight = height; - - _sizeChanged = true; - } - } - - private void Release(object context) - { - if (_release != null) - { - _release(context); - } - } - - private int GetBlitFramebufferHandleLazy() - { - int handle = _blitFramebufferHandle; - - if (handle == 0) - { - handle = GL.GenFramebuffer(); - - _blitFramebufferHandle = handle; - } - - return handle; + _width = width; + _height = height; } private int GetCopyFramebufferHandleLazy() { int handle = _copyFramebufferHandle; - void GenerateAndBindTexture() - { - int textureHandle = GenerateWindowTexture(); - - GL.BindFramebuffer(FramebufferTarget.Framebuffer, handle); - - GL.FramebufferTexture( - FramebufferTarget.Framebuffer, - FramebufferAttachment.ColorAttachment0, - textureHandle, - 0); - - _screenTextureHandle = textureHandle; - } - if (handle == 0) { handle = GL.GenFramebuffer(); _copyFramebufferHandle = handle; - - GenerateAndBindTexture(); } - else if (_sizeChanged) - { - GL.DeleteTexture(_screenTextureHandle); - - lock (_resizeLocker) - { - _width = _resizeWidth; - _height = _resizeHeight; - - _sizeChanged = false; - } - - GenerateAndBindTexture(); - } - - return handle; - } - - private int GenerateWindowTexture() - { - int handle = GL.GenTexture(); - - GL.BindTexture(TextureTarget.Texture2D, handle); - - GL.TexImage2D( - TextureTarget.Texture2D, - 0, - PixelInternalFormat.Rgba8, - _width, - _height, - 0, - PixelFormat.Rgba, - PixelType.UnsignedByte, - IntPtr.Zero); return handle; } diff --git a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/NvFlinger.cs b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/NvFlinger.cs index 50b55ee0..fa798177 100644 --- a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/NvFlinger.cs +++ b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/NvFlinger.cs @@ -1,7 +1,7 @@ using Ryujinx.Common.Logging; using Ryujinx.Graphics.GAL; +using Ryujinx.Graphics.Gpu; using Ryujinx.HLE.HOS.Kernel.Threading; -using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu; using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap; using System; using System.Collections.Generic; @@ -295,11 +295,6 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger _bufferQueue[slot].State = BufferState.Acquired; - Rect crop = _bufferQueue[slot].Crop; - - bool flipX = _bufferQueue[slot].Transform.HasFlag(HalTransform.FlipX); - bool flipY = _bufferQueue[slot].Transform.HasFlag(HalTransform.FlipY); - Format format = ConvertColorFormat(_bufferQueue[slot].Data.Buffer.Surfaces[0].ColorFormat); int bytesPerPixel = @@ -310,7 +305,20 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger // Note: Rotation is being ignored. - ITexture texture = context.Device.Gpu.GetTexture( + Rect cropRect = _bufferQueue[slot].Crop; + + bool flipX = _bufferQueue[slot].Transform.HasFlag(HalTransform.FlipX); + bool flipY = _bufferQueue[slot].Transform.HasFlag(HalTransform.FlipY); + + ImageCrop crop = new ImageCrop( + cropRect.Left, + cropRect.Right, + cropRect.Top, + cropRect.Bottom, + flipX, + flipY); + + context.Device.Gpu.Window.EnqueueFrameThreadSafe( fbAddr, fbWidth, fbHeight, @@ -318,24 +326,15 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger false, gobBlocksInY, format, - bytesPerPixel); - - _renderer.Window.RegisterTextureReleaseCallback(ReleaseBuffer); - - ImageCrop imageCrop = new ImageCrop( - crop.Left, - crop.Right, - crop.Top, - crop.Bottom, - flipX, - flipY); - - _renderer.Window.QueueTexture(texture, imageCrop, slot); + bytesPerPixel, + crop, + ReleaseBuffer, + slot); } - private void ReleaseBuffer(object context) + private void ReleaseBuffer(object slot) { - ReleaseBuffer((int)context); + ReleaseBuffer((int)slot); } private void ReleaseBuffer(int slot) diff --git a/Ryujinx.HLE/Switch.cs b/Ryujinx.HLE/Switch.cs index e5a5f273..9df1d757 100644 --- a/Ryujinx.HLE/Switch.cs +++ b/Ryujinx.HLE/Switch.cs @@ -122,6 +122,11 @@ namespace Ryujinx.HLE Gpu.DmaPusher.DispatchCalls(); } + public void PresentFrame(Action swapBuffersCallback) + { + Gpu.Window.Present(swapBuffersCallback); + } + internal void Unload() { FileSystem.Dispose(); diff --git a/Ryujinx/Ui/GLScreen.cs b/Ryujinx/Ui/GLScreen.cs index 6d1060ee..1cce6a1f 100644 --- a/Ryujinx/Ui/GLScreen.cs +++ b/Ryujinx/Ui/GLScreen.cs @@ -294,7 +294,7 @@ namespace Ryujinx.Ui private new void RenderFrame() { - _renderer.Window.Present(); + _device.PresentFrame(SwapBuffers); _device.Statistics.RecordSystemFrameTime(); @@ -312,8 +312,6 @@ namespace Ryujinx.Ui _titleEvent = true; - SwapBuffers(); - _device.System.SignalVsync(); _device.VsyncEvent.Set();