diff --git a/Ryujinx.Graphics/Gal/IGalRenderTarget.cs b/Ryujinx.Graphics/Gal/IGalRenderTarget.cs index 6c9166f24d..7ccf0981d1 100644 --- a/Ryujinx.Graphics/Gal/IGalRenderTarget.cs +++ b/Ryujinx.Graphics/Gal/IGalRenderTarget.cs @@ -35,7 +35,5 @@ namespace Ryujinx.Graphics.Gal int DstY1); void Reinterpret(long Key, GalImage NewImage); - - byte[] GetData(long Key); } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLRenderTarget.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLRenderTarget.cs index 7dde32d828..ff5dc1b895 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLRenderTarget.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLRenderTarget.cs @@ -56,6 +56,8 @@ namespace Ryujinx.Graphics.Gal.OpenGL private int DepthAttachment; private int StencilAttachment; + private int CopyPBO; + public OGLRenderTarget(OGLTexture Texture) { ColorAttachments = new int[8]; @@ -358,45 +360,33 @@ namespace Ryujinx.Graphics.Gal.OpenGL return; } - byte[] Data = GetData(Key); + if (CopyPBO == 0) + { + CopyPBO = GL.GenBuffer(); + } - GL.PixelStore(PixelStoreParameter.UnpackRowLength, OldImage.Width); + GL.BindBuffer(BufferTarget.PixelPackBuffer, CopyPBO); - Texture.Create(Key, Data, NewImage); + GL.BufferData(BufferTarget.PixelPackBuffer, Math.Max(ImageUtils.GetSize(OldImage), ImageUtils.GetSize(NewImage)), IntPtr.Zero, BufferUsageHint.StreamCopy); - GL.PixelStore(PixelStoreParameter.UnpackRowLength, 0); - } - - public byte[] GetData(long Key) - { if (!Texture.TryGetImageHandler(Key, out ImageHandler CachedImage)) { - return null; + throw new InvalidOperationException(); } - if (SrcFb == 0) - { - SrcFb = GL.GenFramebuffer(); - } - - GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, SrcFb); - - FramebufferAttachment Attachment = GetAttachment(CachedImage); - - GL.FramebufferTexture(FramebufferTarget.ReadFramebuffer, Attachment, CachedImage.Handle, 0); - - int Size = ImageUtils.GetSize(CachedImage.Image); - - byte[] Data = new byte[Size]; - - int Width = CachedImage.Width; - int Height = CachedImage.Height; - (_, PixelFormat Format, PixelType Type) = OGLEnumConverter.GetImageFormat(CachedImage.Format); - GL.ReadPixels(0, 0, Width, Height, Format, Type, Data); + GL.BindTexture(TextureTarget.Texture2D, CachedImage.Handle); - return Data; + GL.GetTexImage(TextureTarget.Texture2D, 0, Format, Type, IntPtr.Zero); + + GL.BindBuffer(BufferTarget.PixelPackBuffer, 0); + + GL.BindBuffer(BufferTarget.PixelUnpackBuffer, CopyPBO); + + Texture.Create(Key, ImageUtils.GetSize(NewImage), NewImage); + + GL.BindBuffer(BufferTarget.PixelUnpackBuffer, 0); } private static FramebufferAttachment GetAttachment(ImageHandler CachedImage) diff --git a/Ryujinx.Graphics/GpuResourceManager.cs b/Ryujinx.Graphics/GpuResourceManager.cs index ba35910d30..0a8d201452 100644 --- a/Ryujinx.Graphics/GpuResourceManager.cs +++ b/Ryujinx.Graphics/GpuResourceManager.cs @@ -7,10 +7,20 @@ namespace Ryujinx.Graphics { public class GpuResourceManager { + private enum ImageType + { + None, + Texture, + ColorBuffer, + ZetaBuffer + } + private NvGpu Gpu; private HashSet[] UploadedKeys; + private Dictionary ImageTypes; + public GpuResourceManager(NvGpu Gpu) { this.Gpu = Gpu; @@ -21,26 +31,21 @@ namespace Ryujinx.Graphics { UploadedKeys[Index] = new HashSet(); } + + ImageTypes = new Dictionary(); } public void SendColorBuffer(NvGpuVmm Vmm, long Position, int Attachment, GalImage NewImage) { long Size = (uint)ImageUtils.GetSize(NewImage); - MarkAsCached(Vmm, Position, Size, NvGpuBufferType.Texture); + ImageTypes[Position] = ImageType.ColorBuffer; - bool IsCached = Gpu.Renderer.Texture.TryGetImage(Position, out GalImage CachedImage); - - if (IsCached && CachedImage.SizeMatches(NewImage)) + if (!TryReuse(Vmm, Position, NewImage)) { - Gpu.Renderer.RenderTarget.Reinterpret(Position, NewImage); - Gpu.Renderer.RenderTarget.BindColor(Position, Attachment, NewImage); - - return; + Gpu.Renderer.Texture.Create(Position, (int)Size, NewImage); } - Gpu.Renderer.Texture.Create(Position, (int)Size, NewImage); - Gpu.Renderer.RenderTarget.BindColor(Position, Attachment, NewImage); } @@ -48,38 +53,49 @@ namespace Ryujinx.Graphics { long Size = (uint)ImageUtils.GetSize(NewImage); - MarkAsCached(Vmm, Position, Size, NvGpuBufferType.Texture); + ImageTypes[Position] = ImageType.ZetaBuffer; - bool IsCached = Gpu.Renderer.Texture.TryGetImage(Position, out GalImage CachedImage); - - if (IsCached && CachedImage.SizeMatches(NewImage)) + if (!TryReuse(Vmm, Position, NewImage)) { - Gpu.Renderer.RenderTarget.Reinterpret(Position, NewImage); - Gpu.Renderer.RenderTarget.BindZeta(Position, NewImage); - - return; + Gpu.Renderer.Texture.Create(Position, (int)Size, NewImage); } - Gpu.Renderer.Texture.Create(Position, (int)Size, NewImage); - Gpu.Renderer.RenderTarget.BindZeta(Position, NewImage); } public void SendTexture(NvGpuVmm Vmm, long Position, GalImage NewImage, int TexIndex = -1) { - long Size = (uint)ImageUtils.GetSize(NewImage); + PrepareSendTexture(Vmm, Position, NewImage); - if (!MemoryRegionModified(Vmm, Position, Size, NvGpuBufferType.Texture)) + if (TexIndex >= 0) { - if (Gpu.Renderer.Texture.TryGetImage(Position, out GalImage CachedImage) && CachedImage.SizeMatches(NewImage)) + Gpu.Renderer.Texture.Bind(Position, TexIndex, NewImage); + } + + ImageTypes[Position] = ImageType.Texture; + } + + private void PrepareSendTexture(NvGpuVmm Vmm, long Position, GalImage NewImage) + { + long Size = ImageUtils.GetSize(NewImage); + + bool SkipCheck = false; + + if (ImageTypes.TryGetValue(Position, out ImageType OldType)) + { + if (OldType == ImageType.ColorBuffer || OldType == ImageType.ZetaBuffer) { - Gpu.Renderer.RenderTarget.Reinterpret(Position, NewImage); + //Avoid data destruction + MemoryRegionModified(Vmm, Position, Size, NvGpuBufferType.Texture); - if (TexIndex >= 0) - { - Gpu.Renderer.Texture.Bind(Position, TexIndex, NewImage); - } + SkipCheck = true; + } + } + if (SkipCheck || !MemoryRegionModified(Vmm, Position, Size, NvGpuBufferType.Texture)) + { + if (TryReuse(Vmm, Position, NewImage)) + { return; } } @@ -87,16 +103,18 @@ namespace Ryujinx.Graphics byte[] Data = ImageUtils.ReadTexture(Vmm, NewImage, Position); Gpu.Renderer.Texture.Create(Position, Data, NewImage); - - if (TexIndex >= 0) - { - Gpu.Renderer.Texture.Bind(Position, TexIndex, NewImage); - } } - private void MarkAsCached(NvGpuVmm Vmm, long Position, long Size, NvGpuBufferType Type) + private bool TryReuse(NvGpuVmm Vmm, long Position, GalImage NewImage) { - Vmm.IsRegionModified(Position, Size, Type); + if (Gpu.Renderer.Texture.TryGetImage(Position, out GalImage CachedImage) && CachedImage.SizeMatches(NewImage)) + { + Gpu.Renderer.RenderTarget.Reinterpret(Position, NewImage); + + return true; + } + + return false; } private bool MemoryRegionModified(NvGpuVmm Vmm, long Position, long Size, NvGpuBufferType Type)