From deb3c58020c83d8b0be7b342dcefd666a003163c Mon Sep 17 00:00:00 2001 From: Thog Date: Mon, 24 Dec 2018 15:21:02 +0100 Subject: [PATCH] Support 2D array copy operation in the 2D engine This make every copy right in the GPU side. Thie CPU copy probably needs to be updated --- Ryujinx.Graphics/Gal/IGalRenderTarget.cs | 24 +++++---- .../Gal/OpenGL/OGLRenderTarget.cs | 44 ++++++++++----- Ryujinx.Graphics/GpuResourceManager.cs | 28 ++++++++++ Ryujinx.Graphics/Graphics3d/NvGpuEngine2d.cs | 53 ++++++++++++++++++- .../Graphics3d/NvGpuEngine2dReg.cs | 2 + 5 files changed, 128 insertions(+), 23 deletions(-) diff --git a/Ryujinx.Graphics/Gal/IGalRenderTarget.cs b/Ryujinx.Graphics/Gal/IGalRenderTarget.cs index f941ccd584..90cad856d9 100644 --- a/Ryujinx.Graphics/Gal/IGalRenderTarget.cs +++ b/Ryujinx.Graphics/Gal/IGalRenderTarget.cs @@ -25,16 +25,20 @@ namespace Ryujinx.Graphics.Gal void Render(); void Copy( - long SrcKey, - long DstKey, - int SrcX0, - int SrcY0, - int SrcX1, - int SrcY1, - int DstX0, - int DstY0, - int DstX1, - int DstY1); + GalImage SrcImage, + GalImage DstImage, + long SrcKey, + long DstKey, + int SrcLayer, + int DstLayer, + int SrcX0, + int SrcY0, + int SrcX1, + int SrcY1, + int DstX0, + int DstY0, + int DstX1, + int DstY1); void Reinterpret(long Key, GalImage NewImage); } diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLRenderTarget.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLRenderTarget.cs index e0eb6201a0..2de5fe3b35 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLRenderTarget.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLRenderTarget.cs @@ -389,16 +389,20 @@ namespace Ryujinx.Graphics.Gal.OpenGL } public void Copy( - long SrcKey, - long DstKey, - int SrcX0, - int SrcY0, - int SrcX1, - int SrcY1, - int DstX0, - int DstY0, - int DstX1, - int DstY1) + GalImage SrcImage, + GalImage DstImage, + long SrcKey, + long DstKey, + int SrcLayer, + int DstLayer, + int SrcX0, + int SrcY0, + int SrcX1, + int SrcY1, + int DstX0, + int DstY0, + int DstX1, + int DstY1) { if (Texture.TryGetImageHandler(SrcKey, out ImageHandler SrcTex) && Texture.TryGetImageHandler(DstKey, out ImageHandler DstTex)) @@ -425,8 +429,24 @@ namespace Ryujinx.Graphics.Gal.OpenGL FramebufferAttachment Attachment = GetAttachment(SrcTex); - GL.FramebufferTexture(FramebufferTarget.ReadFramebuffer, Attachment, SrcTex.Handle, 0); - GL.FramebufferTexture(FramebufferTarget.DrawFramebuffer, Attachment, DstTex.Handle, 0); + if (ImageUtils.IsArray(SrcImage.TextureTarget) && SrcLayer > 0) + { + GL.FramebufferTextureLayer(FramebufferTarget.ReadFramebuffer, Attachment, SrcTex.Handle, 0, SrcLayer); + } + else + { + GL.FramebufferTexture(FramebufferTarget.ReadFramebuffer, Attachment, SrcTex.Handle, 0); + } + + if (ImageUtils.IsArray(DstImage.TextureTarget) && DstLayer > 0) + { + GL.FramebufferTextureLayer(FramebufferTarget.DrawFramebuffer, Attachment, DstTex.Handle, 0, DstLayer); + } + else + { + GL.FramebufferTexture(FramebufferTarget.DrawFramebuffer, Attachment, DstTex.Handle, 0); + } + BlitFramebufferFilter Filter = BlitFramebufferFilter.Nearest; diff --git a/Ryujinx.Graphics/GpuResourceManager.cs b/Ryujinx.Graphics/GpuResourceManager.cs index d46129516d..134ba36faa 100644 --- a/Ryujinx.Graphics/GpuResourceManager.cs +++ b/Ryujinx.Graphics/GpuResourceManager.cs @@ -1,6 +1,7 @@ using Ryujinx.Graphics.Gal; using Ryujinx.Graphics.Memory; using Ryujinx.Graphics.Texture; +using System; using System.Collections.Generic; namespace Ryujinx.Graphics @@ -11,6 +12,7 @@ namespace Ryujinx.Graphics { None, Texture, + TextureMirror, ColorBuffer, ZetaBuffer } @@ -20,6 +22,7 @@ namespace Ryujinx.Graphics private HashSet[] UploadedKeys; private Dictionary ImageTypes; + private Dictionary MirroredTextures; public GpuResourceManager(NvGpu Gpu) { @@ -33,6 +36,7 @@ namespace Ryujinx.Graphics } ImageTypes = new Dictionary(); + MirroredTextures = new Dictionary(); } public void SendColorBuffer(NvGpuVmm Vmm, long Position, int Attachment, GalImage NewImage) @@ -70,6 +74,30 @@ namespace Ryujinx.Graphics ImageTypes[Position] = ImageType.Texture; } + public bool TryGetTextureMirorLayer(long Position, out int Layer) + { + if (MirroredTextures.TryGetValue(Position, out Layer)) + { + ImageType Type = ImageTypes[Position]; + + if (Type != ImageType.Texture && Type != ImageType.TextureMirror) + { + throw new InvalidOperationException(); + } + + return true; + } + + Layer = -1; + return false; + } + + public void SetTextureMirror(long Position, int Layer) + { + ImageTypes[Position] = ImageType.TextureMirror; + MirroredTextures[Position] = Layer; + } + private void PrepareSendTexture(NvGpuVmm Vmm, long Position, GalImage NewImage) { long Size = ImageUtils.GetSize(NewImage); diff --git a/Ryujinx.Graphics/Graphics3d/NvGpuEngine2d.cs b/Ryujinx.Graphics/Graphics3d/NvGpuEngine2d.cs index 1a58c4901c..b591def8af 100644 --- a/Ryujinx.Graphics/Graphics3d/NvGpuEngine2d.cs +++ b/Ryujinx.Graphics/Graphics3d/NvGpuEngine2d.cs @@ -86,12 +86,16 @@ namespace Ryujinx.Graphics.Graphics3d long SrcKey = Vmm.GetPhysicalAddress(SrcAddress); long DstKey = Vmm.GetPhysicalAddress(DstAddress); + bool IsSrcLayered = false; + bool IsDstLayered = false; + GalTextureTarget SrcTarget = GalTextureTarget.TwoD; if (SrcDepth != 0) { SrcTarget = GalTextureTarget.TwoDArray; SrcDepth++; + IsSrcLayered = true; } else { @@ -104,6 +108,7 @@ namespace Ryujinx.Graphics.Graphics3d { DstTarget = GalTextureTarget.TwoDArray; DstDepth++; + IsDstLayered = true; } else { @@ -131,19 +136,63 @@ namespace Ryujinx.Graphics.Graphics3d SrcTexture.Pitch = SrcPitch; DstTexture.Pitch = DstPitch; + long GetLayerOffset(GalImage Image, int Layer) + { + // FIXME: CALCULATE THE REAL TEXTURE SIZE (GPU SIZE NOT OGL SIZE) + // TODO: mip map + return ImageUtils.GetSize(Image) * Layer; + } + + int SrcLayerIndex = -1; + + if (IsSrcLayered && Gpu.ResourceManager.TryGetTextureMirorLayer(SrcKey, out SrcLayerIndex)) + { + SrcKey = SrcKey - GetLayerOffset(SrcTexture, SrcLayerIndex); + } + + int DstLayerIndex = -1; + + if (IsDstLayered && Gpu.ResourceManager.TryGetTextureMirorLayer(DstKey, out DstLayerIndex)) + { + DstKey = DstKey - GetLayerOffset(DstTexture, DstLayerIndex); + } + Gpu.ResourceManager.SendTexture(Vmm, SrcKey, SrcTexture); Gpu.ResourceManager.SendTexture(Vmm, DstKey, DstTexture); + if (IsSrcLayered && SrcLayerIndex == -1) + { + for (int Layer = 0; Layer < SrcTexture.Depth; Layer++) + { + Gpu.ResourceManager.SetTextureMirror(SrcKey + GetLayerOffset(SrcTexture, Layer), Layer); + } + + SrcLayerIndex = 0; + } + + if (IsDstLayered && DstLayerIndex == -1) + { + for (int Layer = 0; Layer < DstTexture.Depth; Layer++) + { + Gpu.ResourceManager.SetTextureMirror(DstKey + GetLayerOffset(DstTexture, Layer), Layer); + } + + DstLayerIndex = 0; + } + int SrcBlitX1 = (int)(SrcBlitX >> 32); int SrcBlitY1 = (int)(SrcBlitY >> 32); int SrcBlitX2 = (int)(SrcBlitX + DstBlitW * BlitDuDx >> 32); int SrcBlitY2 = (int)(SrcBlitY + DstBlitH * BlitDvDy >> 32); - // TODO: support 2d array copy Gpu.Renderer.RenderTarget.Copy( + SrcTexture, + DstTexture, SrcKey, DstKey, + SrcLayerIndex, + DstLayerIndex, SrcBlitX1, SrcBlitY1, SrcBlitX2, @@ -157,6 +206,8 @@ namespace Ryujinx.Graphics.Graphics3d //the texture is modified by the guest, however it doesn't //work when resources that the gpu can write to are copied, //like framebuffers. + + // FIXME: SUPPORT MULTILAYER CORRECTLY HERE (this will cause weird stuffs on the first layer) ImageUtils.CopyTexture( Vmm, SrcTexture, diff --git a/Ryujinx.Graphics/Graphics3d/NvGpuEngine2dReg.cs b/Ryujinx.Graphics/Graphics3d/NvGpuEngine2dReg.cs index c1c0dba29f..7747b5a3ab 100644 --- a/Ryujinx.Graphics/Graphics3d/NvGpuEngine2dReg.cs +++ b/Ryujinx.Graphics/Graphics3d/NvGpuEngine2dReg.cs @@ -11,6 +11,7 @@ namespace Ryujinx.Graphics.Graphics3d DstWidth = 0x86, DstHeight = 0x87, DstAddress = 0x88, + DstAddressLow = 0x89, SrcFormat = 0x8c, SrcLinear = 0x8d, SrcBlockDimensions = 0x8e, @@ -20,6 +21,7 @@ namespace Ryujinx.Graphics.Graphics3d SrcWidth = 0x92, SrcHeight = 0x93, SrcAddress = 0x94, + SrcAddressLow = 0x95, ClipEnable = 0xa4, CopyOperation = 0xab, BlitControl = 0x223,