Просмотр исходного кода

General improvements for GpuResourceManager (#421)

* General improvements to GpuResourceManager

* Address feedback

* Address feedback
ReinUsesLisp 7 лет назад
Родитель
Сommit
bed13f2022

+ 0 - 2
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);
     }
 }

+ 16 - 26
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);
-
-            GL.PixelStore(PixelStoreParameter.UnpackRowLength, OldImage.Width);
+            if (CopyPBO == 0)
+            {
+                CopyPBO = GL.GenBuffer();
+            }
 
-            Texture.Create(Key, Data, NewImage);
+            GL.BindBuffer(BufferTarget.PixelPackBuffer, CopyPBO);
 
-            GL.PixelStore(PixelStoreParameter.UnpackRowLength, 0);
-        }
+            GL.BufferData(BufferTarget.PixelPackBuffer, Math.Max(ImageUtils.GetSize(OldImage), ImageUtils.GetSize(NewImage)), IntPtr.Zero, BufferUsageHint.StreamCopy);
 
-        public byte[] GetData(long Key)
-        {
             if (!Texture.TryGetImageHandler(Key, out ImageHandler CachedImage))
             {
-                return null;
-            }
-
-            if (SrcFb == 0)
-            {
-                SrcFb = GL.GenFramebuffer();
+                throw new InvalidOperationException();
             }
 
-            GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, SrcFb);
-
-            FramebufferAttachment Attachment = GetAttachment(CachedImage);
-
-            GL.FramebufferTexture(FramebufferTarget.ReadFramebuffer, Attachment, CachedImage.Handle, 0);
+            (_, PixelFormat Format, PixelType Type) = OGLEnumConverter.GetImageFormat(CachedImage.Format);
 
-            int Size = ImageUtils.GetSize(CachedImage.Image);
+            GL.BindTexture(TextureTarget.Texture2D, CachedImage.Handle);
 
-            byte[] Data = new byte[Size];
+            GL.GetTexImage(TextureTarget.Texture2D, 0, Format, Type, IntPtr.Zero);
 
-            int Width  = CachedImage.Width;
-            int Height = CachedImage.Height;
+            GL.BindBuffer(BufferTarget.PixelPackBuffer, 0);
 
-            (_, PixelFormat Format, PixelType Type) = OGLEnumConverter.GetImageFormat(CachedImage.Format);
+            GL.BindBuffer(BufferTarget.PixelUnpackBuffer, CopyPBO);
 
-            GL.ReadPixels(0, 0, Width, Height, Format, Type, Data);
+            Texture.Create(Key, ImageUtils.GetSize(NewImage), NewImage);
 
-            return Data;
+            GL.BindBuffer(BufferTarget.PixelUnpackBuffer, 0);
         }
 
         private static FramebufferAttachment GetAttachment(ImageHandler CachedImage)

+ 52 - 34
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<long>[] UploadedKeys;
 
+        private Dictionary<long, ImageType> ImageTypes;
+
         public GpuResourceManager(NvGpu Gpu)
         {
             this.Gpu = Gpu;
@@ -21,26 +31,21 @@ namespace Ryujinx.Graphics
             {
                 UploadedKeys[Index] = new HashSet<long>();
             }
+
+            ImageTypes = new Dictionary<long, ImageType>();
         }
 
         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 (TexIndex >= 0)
+            {
+                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);
 
-            if (!MemoryRegionModified(Vmm, Position, Size, NvGpuBufferType.Texture))
+            bool SkipCheck = false;
+
+            if (ImageTypes.TryGetValue(Position, out ImageType OldType))
             {
-                if (Gpu.Renderer.Texture.TryGetImage(Position, out GalImage CachedImage) && CachedImage.SizeMatches(NewImage))
+                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)
+        private bool TryReuse(NvGpuVmm Vmm, long Position, GalImage NewImage)
+        {
+            if (Gpu.Renderer.Texture.TryGetImage(Position, out GalImage CachedImage) && CachedImage.SizeMatches(NewImage))
             {
-                Gpu.Renderer.Texture.Bind(Position, TexIndex, NewImage);
+                Gpu.Renderer.RenderTarget.Reinterpret(Position, NewImage);
+
+                return true;
             }
-        }
 
-        private void MarkAsCached(NvGpuVmm Vmm, long Position, long Size, NvGpuBufferType Type)
-        {
-            Vmm.IsRegionModified(Position, Size, Type);
+            return false;
         }
 
         private bool MemoryRegionModified(NvGpuVmm Vmm, long Position, long Size, NvGpuBufferType Type)