diff --git a/Ryujinx.Graphics/Gal/GalTexture.cs b/Ryujinx.Graphics/Gal/GalTexture.cs new file mode 100644 index 0000000000..fcf1f1ad2b --- /dev/null +++ b/Ryujinx.Graphics/Gal/GalTexture.cs @@ -0,0 +1,20 @@ +namespace Ryujinx.Graphics.Gal +{ + public struct GalTexture + { + public byte[] Data; + + public int Width; + public int Height; + + public GalTextureFormat Format; + + public GalTexture(byte[] Data, int Width, int Height, GalTextureFormat Format) + { + this.Data = Data; + this.Width = Width; + this.Height = Height; + this.Format = Format; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/GalTextureFormat.cs b/Ryujinx.Graphics/Gal/GalTextureFormat.cs new file mode 100644 index 0000000000..cf948526a5 --- /dev/null +++ b/Ryujinx.Graphics/Gal/GalTextureFormat.cs @@ -0,0 +1,10 @@ +namespace Ryujinx.Graphics.Gal +{ + public enum GalTextureFormat + { + A8B8G8R8 = 0x8, + BC1 = 0x24, + BC2 = 0x25, + BC3 = 0x26 + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/IGalRenderer.cs b/Ryujinx.Graphics/Gal/IGalRenderer.cs index bafa16bd46..2503b8e6cb 100644 --- a/Ryujinx.Graphics/Gal/IGalRenderer.cs +++ b/Ryujinx.Graphics/Gal/IGalRenderer.cs @@ -25,16 +25,19 @@ namespace Ryujinx.Graphics.Gal void ClearBuffers(int RtIndex, GalClearBufferFlags Flags); void SetVertexArray(int VbIndex, int Stride, byte[] Buffer, GalVertexAttrib[] Attribs); + void RenderVertexArray(int VbIndex); //Shader void CreateShader(long Tag, GalShaderType Type, byte[] Data); - void SetShaderCb(long Tag, int Cbuf, byte[] Data); + + void SetShaderConstBuffer(long Tag, int Cbuf, byte[] Data); + void BindShader(long Tag); + void BindProgram(); - void SendR8G8B8A8Texture(int Index, byte[] Buffer, int Width, int Height); - - void BindTexture(int Index); + //Texture + void UpdateTextures(Func RequestTextureCallback); } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs index 16d5a87e83..571aa2074f 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs @@ -87,6 +87,25 @@ namespace Ryujinx.Graphics.Gal.OpenGL } } + public IEnumerable GetTextureUsage(GalShaderType ShaderType) + { + switch (ShaderType) + { + case GalShaderType.Vertex: return GetTextureUsage(Current.Vertex); + case GalShaderType.TessControl: return GetTextureUsage(Current.TessControl); + case GalShaderType.TessEvaluation: return GetTextureUsage(Current.TessEvaluation); + case GalShaderType.Geometry: return GetTextureUsage(Current.Geometry); + case GalShaderType.Fragment: return GetTextureUsage(Current.Fragment); + } + + return null; + } + + private IEnumerable GetTextureUsage(ShaderStage Stage) + { + return Stage?.TextureUsage ?? Enumerable.Empty(); + } + public void SetConstBuffer(long Tag, int Cbuf, byte[] Data) { if (Stages.TryGetValue(Tag, out ShaderStage Stage)) diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs new file mode 100644 index 0000000000..66ada4a989 --- /dev/null +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs @@ -0,0 +1,87 @@ +using OpenTK.Graphics.OpenGL; +using Ryujinx.Graphics.Gal.Texture; +using System; + +namespace Ryujinx.Graphics.Gal.OpenGL +{ + class OGLTexture + { + private OGLShader Shader; + + private int[] Textures; + + private int CurrentTextureIndex; + + public OGLTexture(OGLShader Shader) + { + this.Shader = Shader; + + Textures = new int[80]; + } + + public void UpdateTextures(Func RequestTextureCallback) + { + CurrentTextureIndex = 0; + + UpdateTextures(RequestTextureCallback, GalShaderType.Vertex); + UpdateTextures(RequestTextureCallback, GalShaderType.TessControl); + UpdateTextures(RequestTextureCallback, GalShaderType.TessEvaluation); + UpdateTextures(RequestTextureCallback, GalShaderType.Geometry); + UpdateTextures(RequestTextureCallback, GalShaderType.Fragment); + } + + private void UpdateTextures(Func RequestTextureCallback, GalShaderType ShaderType) + { + foreach (ShaderDeclInfo DeclInfo in Shader.GetTextureUsage(ShaderType)) + { + GalTexture Texture = RequestTextureCallback(DeclInfo.Index, ShaderType); + + GL.ActiveTexture(TextureUnit.Texture0 + CurrentTextureIndex); + + UploadTexture(Texture); + + int Location = GL.GetUniformLocation(Shader.CurrentProgramHandle, DeclInfo.Name); + + GL.Uniform1(Location, CurrentTextureIndex++); + } + } + + private void UploadTexture(GalTexture Texture) + { + int Handle = EnsureTextureInitialized(CurrentTextureIndex); + + GL.BindTexture(TextureTarget.Texture2D, Handle); + + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.Repeat); + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.Repeat); + + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear); + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear); + + const PixelInternalFormat Pif = PixelInternalFormat.Rgba; + + int W = Texture.Width; + int H = Texture.Height; + + const PixelFormat Pf = PixelFormat.Rgba; + + const PixelType Pt = PixelType.UnsignedByte; + + byte[] Buffer = TextureDecoder.Decode(Texture); + + GL.TexImage2D(TextureTarget.Texture2D, 0, Pif, W, H, 0, Pf, Pt, Buffer); + } + + private int EnsureTextureInitialized(int TextureIndex) + { + int Handle = Textures[TextureIndex]; + + if (Handle == 0) + { + Handle = Textures[TextureIndex] = GL.GenTexture(); + } + + return Handle; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs b/Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs index a8e2e79022..985ef17d19 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs @@ -1,5 +1,4 @@ using OpenTK; -using OpenTK.Graphics.OpenGL; using System; using System.Collections.Concurrent; @@ -7,29 +6,24 @@ namespace Ryujinx.Graphics.Gal.OpenGL { public class OpenGLRenderer : IGalRenderer { - private struct Texture - { - public int Handle; - } - - private Texture[] Textures; - private OGLRasterizer Rasterizer; private OGLShader Shader; + private OGLTexture Texture; + private ConcurrentQueue ActionsQueue; private FrameBuffer FbRenderer; public OpenGLRenderer() { - Textures = new Texture[8]; - Rasterizer = new OGLRasterizer(); Shader = new OGLShader(); + Texture = new OGLTexture(Shader); + ActionsQueue = new ConcurrentQueue(); } @@ -116,33 +110,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL ActionsQueue.Enqueue(() => Rasterizer.RenderVertexArray(VbIndex)); } - public void SendR8G8B8A8Texture(int Index, byte[] Buffer, int Width, int Height) - { - EnsureTexInitialized(Index); - - GL.BindTexture(TextureTarget.Texture2D, Textures[Index].Handle); - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.Repeat); - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.Repeat); - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear); - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear); - GL.TexImage2D(TextureTarget.Texture2D, - 0, - PixelInternalFormat.Rgba, - Width, - Height, - 0, - PixelFormat.Rgba, - PixelType.UnsignedByte, - Buffer); - } - - public void BindTexture(int Index) - { - GL.ActiveTexture(TextureUnit.Texture0 + Index); - - GL.BindTexture(TextureTarget.Texture2D, Textures[Index].Handle); - } - public void CreateShader(long Tag, GalShaderType Type, byte[] Data) { if (Data == null) @@ -153,7 +120,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL ActionsQueue.Enqueue(() => Shader.Create(Tag, Type, Data)); } - public void SetShaderCb(long Tag, int Cbuf, byte[] Data) + public void SetShaderConstBuffer(long Tag, int Cbuf, byte[] Data) { if (Data == null) { @@ -173,16 +140,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL ActionsQueue.Enqueue(() => Shader.BindProgram()); } - private void EnsureTexInitialized(int TexIndex) + public void UpdateTextures(Func RequestTextureCallback) { - Texture Tex = Textures[TexIndex]; - - if (Tex.Handle == 0) - { - Tex.Handle = GL.GenTexture(); - } - - Textures[TexIndex] = Tex; + ActionsQueue.Enqueue(() => Texture.UpdateTextures(RequestTextureCallback)); } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs b/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs index e957d13c63..b0f9886d84 100644 --- a/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs +++ b/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs @@ -112,7 +112,7 @@ namespace Ryujinx.Graphics.Gal.Shader string Name = StagePrefix + TextureName + Index; - m_Textures.TryAdd(Handle, new ShaderDeclInfo(Name, Index)); + m_Textures.TryAdd(Handle, new ShaderDeclInfo(Name, Handle)); } break; } diff --git a/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs b/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs index 0f89eb2f0d..3426c0a366 100644 --- a/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs +++ b/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs @@ -282,7 +282,8 @@ namespace Ryujinx.Graphics.Gal.Shader throw new NotImplementedException(Op.Inst.ToString()); } - if (!(Entry || IsUnary(Op.Inst))) + if (!Entry && (Op.OperandB != null || + Op.OperandC != null)) { Expr = "(" + Expr + ")"; } @@ -293,24 +294,6 @@ namespace Ryujinx.Graphics.Gal.Shader } } - private bool IsUnary(ShaderIrInst Inst) - { - return Inst == ShaderIrInst.Bnot || - Inst == ShaderIrInst.Fabs || - Inst == ShaderIrInst.Fcos || - Inst == ShaderIrInst.Fex2 || - Inst == ShaderIrInst.Flg2 || - Inst == ShaderIrInst.Fneg || - Inst == ShaderIrInst.Frcp || - Inst == ShaderIrInst.Frsq || - Inst == ShaderIrInst.Fsin || - Inst == ShaderIrInst.Ipa || - Inst == ShaderIrInst.Texr || - Inst == ShaderIrInst.Texg || - Inst == ShaderIrInst.Texb || - Inst == ShaderIrInst.Texa; - } - private string GetName(ShaderIrOperCbuf Cbuf) { if (!Decl.Uniforms.TryGetValue((Cbuf.Index, Cbuf.Offs), out ShaderDeclInfo DeclInfo)) @@ -331,12 +314,12 @@ namespace Ryujinx.Graphics.Gal.Shader return GetName(Decl.InAttributes, Abuf); } - private string GetName(IReadOnlyDictionary Decls, ShaderIrOperAbuf Abuf) + private string GetName(IReadOnlyDictionary Dict, ShaderIrOperAbuf Abuf) { int Index = Abuf.Offs >> 4; int Elem = (Abuf.Offs >> 2) & 3; - if (!Decls.TryGetValue(Index, out ShaderDeclInfo DeclInfo)) + if (!Dict.TryGetValue(Index, out ShaderDeclInfo DeclInfo)) { throw new InvalidOperationException(); } @@ -359,11 +342,11 @@ namespace Ryujinx.Graphics.Gal.Shader return Pred.IsConst ? "true" : GetNameWithSwizzle(Decl.Preds, Pred.Index); } - private string GetNameWithSwizzle(IReadOnlyDictionary Decls, int Index) + private string GetNameWithSwizzle(IReadOnlyDictionary Dict, int Index) { int VecIndex = Index >> 2; - if (Decls.TryGetValue(VecIndex, out ShaderDeclInfo DeclInfo)) + if (Dict.TryGetValue(VecIndex, out ShaderDeclInfo DeclInfo)) { if (DeclInfo.Size > 1 && Index < VecIndex + DeclInfo.Size) { @@ -371,7 +354,7 @@ namespace Ryujinx.Graphics.Gal.Shader } } - if (!Decls.TryGetValue(Index, out DeclInfo)) + if (!Dict.TryGetValue(Index, out DeclInfo)) { throw new InvalidOperationException(); } @@ -385,6 +368,7 @@ namespace Ryujinx.Graphics.Gal.Shader } private string GetBandExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "&&"); + private string GetBnotExpr(ShaderIrOp Op) => GetUnaryExpr(Op, "!"); private string GetCltExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "<"); @@ -471,9 +455,8 @@ namespace Ryujinx.Graphics.Gal.Shader private string GetTexSamplerCoords(ShaderIrOp Op) { - return "vec2(" + - GetInOperName(Op.OperandA) + ", " + - GetInOperName(Op.OperandB) + ")"; + return "vec2(" + GetInOperName(Op.OperandA, Entry: true) + ", " + + GetInOperName(Op.OperandB, Entry: true) + ")"; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gpu/BCn.cs b/Ryujinx.Graphics/Gal/Texture/BCn.cs similarity index 85% rename from Ryujinx.Graphics/Gpu/BCn.cs rename to Ryujinx.Graphics/Gal/Texture/BCn.cs index b1caf46751..f23a86c2c6 100644 --- a/Ryujinx.Graphics/Gpu/BCn.cs +++ b/Ryujinx.Graphics/Gal/Texture/BCn.cs @@ -1,14 +1,14 @@ using System; using System.Drawing; -namespace Ryujinx.Graphics.Gpu +namespace Ryujinx.Graphics.Gal.Texture { static class BCn { - public static byte[] DecodeBC1(NsGpuTexture Tex, int Offset) + public static byte[] DecodeBC1(GalTexture Texture, int Offset) { - int W = (Tex.Width + 3) / 4; - int H = (Tex.Height + 3) / 4; + int W = (Texture.Width + 3) / 4; + int H = (Texture.Height + 3) / 4; byte[] Output = new byte[W * H * 64]; @@ -20,7 +20,7 @@ namespace Ryujinx.Graphics.Gpu { int IOffs = Offset + Swizzle.GetSwizzledAddress64(X, Y) * 8; - byte[] Tile = BCnDecodeTile(Tex.Data, IOffs, true); + byte[] Tile = BCnDecodeTile(Texture.Data, IOffs, true); int TOffset = 0; @@ -44,10 +44,10 @@ namespace Ryujinx.Graphics.Gpu return Output; } - public static byte[] DecodeBC2(NsGpuTexture Tex, int Offset) + public static byte[] DecodeBC2(GalTexture Texture, int Offset) { - int W = (Tex.Width + 3) / 4; - int H = (Tex.Height + 3) / 4; + int W = (Texture.Width + 3) / 4; + int H = (Texture.Height + 3) / 4; byte[] Output = new byte[W * H * 64]; @@ -59,10 +59,10 @@ namespace Ryujinx.Graphics.Gpu { int IOffs = Offset + Swizzle.GetSwizzledAddress128(X, Y) * 16; - byte[] Tile = BCnDecodeTile(Tex.Data, IOffs + 8, false); + byte[] Tile = BCnDecodeTile(Texture.Data, IOffs + 8, false); - int AlphaLow = Get32(Tex.Data, IOffs + 0); - int AlphaHigh = Get32(Tex.Data, IOffs + 4); + int AlphaLow = Get32(Texture.Data, IOffs + 0); + int AlphaHigh = Get32(Texture.Data, IOffs + 4); ulong AlphaCh = (uint)AlphaLow | (ulong)AlphaHigh << 32; @@ -90,10 +90,10 @@ namespace Ryujinx.Graphics.Gpu return Output; } - public static byte[] DecodeBC3(NsGpuTexture Tex, int Offset) + public static byte[] DecodeBC3(GalTexture Texture, int Offset) { - int W = (Tex.Width + 3) / 4; - int H = (Tex.Height + 3) / 4; + int W = (Texture.Width + 3) / 4; + int H = (Texture.Height + 3) / 4; byte[] Output = new byte[W * H * 64]; @@ -105,17 +105,17 @@ namespace Ryujinx.Graphics.Gpu { int IOffs = Offset + Swizzle.GetSwizzledAddress128(X, Y) * 16; - byte[] Tile = BCnDecodeTile(Tex.Data, IOffs + 8, false); + byte[] Tile = BCnDecodeTile(Texture.Data, IOffs + 8, false); byte[] Alpha = new byte[8]; - Alpha[0] = Tex.Data[IOffs + 0]; - Alpha[1] = Tex.Data[IOffs + 1]; + Alpha[0] = Texture.Data[IOffs + 0]; + Alpha[1] = Texture.Data[IOffs + 1]; CalculateBC3Alpha(Alpha); - int AlphaLow = Get32(Tex.Data, IOffs + 2); - int AlphaHigh = Get16(Tex.Data, IOffs + 6); + int AlphaLow = Get32(Texture.Data, IOffs + 2); + int AlphaHigh = Get16(Texture.Data, IOffs + 6); ulong AlphaCh = (uint)AlphaLow | (ulong)AlphaHigh << 32; @@ -143,10 +143,10 @@ namespace Ryujinx.Graphics.Gpu return Output; } - public static byte[] DecodeBC4(NsGpuTexture Tex, int Offset) + public static byte[] DecodeBC4(GalTexture Texture, int Offset) { - int W = (Tex.Width + 3) / 4; - int H = (Tex.Height + 3) / 4; + int W = (Texture.Width + 3) / 4; + int H = (Texture.Height + 3) / 4; byte[] Output = new byte[W * H * 64]; @@ -160,13 +160,13 @@ namespace Ryujinx.Graphics.Gpu byte[] Red = new byte[8]; - Red[0] = Tex.Data[IOffs + 0]; - Red[1] = Tex.Data[IOffs + 1]; + Red[0] = Texture.Data[IOffs + 0]; + Red[1] = Texture.Data[IOffs + 1]; CalculateBC3Alpha(Red); - int RedLow = Get32(Tex.Data, IOffs + 2); - int RedHigh = Get16(Tex.Data, IOffs + 6); + int RedLow = Get32(Texture.Data, IOffs + 2); + int RedHigh = Get16(Texture.Data, IOffs + 6); ulong RedCh = (uint)RedLow | (ulong)RedHigh << 32; @@ -194,10 +194,10 @@ namespace Ryujinx.Graphics.Gpu return Output; } - public static byte[] DecodeBC5(NsGpuTexture Tex, int Offset, bool SNorm) + public static byte[] DecodeBC5(GalTexture Texture, int Offset, bool SNorm) { - int W = (Tex.Width + 3) / 4; - int H = (Tex.Height + 3) / 4; + int W = (Texture.Width + 3) / 4; + int H = (Texture.Height + 3) / 4; byte[] Output = new byte[W * H * 64]; @@ -212,11 +212,11 @@ namespace Ryujinx.Graphics.Gpu byte[] Red = new byte[8]; byte[] Green = new byte[8]; - Red[0] = Tex.Data[IOffs + 0]; - Red[1] = Tex.Data[IOffs + 1]; + Red[0] = Texture.Data[IOffs + 0]; + Red[1] = Texture.Data[IOffs + 1]; - Green[0] = Tex.Data[IOffs + 8]; - Green[1] = Tex.Data[IOffs + 9]; + Green[0] = Texture.Data[IOffs + 8]; + Green[1] = Texture.Data[IOffs + 9]; if (SNorm) { @@ -229,11 +229,11 @@ namespace Ryujinx.Graphics.Gpu CalculateBC3Alpha(Green); } - int RedLow = Get32(Tex.Data, IOffs + 2); - int RedHigh = Get16(Tex.Data, IOffs + 6); + int RedLow = Get32(Texture.Data, IOffs + 2); + int RedHigh = Get16(Texture.Data, IOffs + 6); - int GreenLow = Get32(Tex.Data, IOffs + 10); - int GreenHigh = Get16(Tex.Data, IOffs + 14); + int GreenLow = Get32(Texture.Data, IOffs + 10); + int GreenHigh = Get16(Texture.Data, IOffs + 14); ulong RedCh = (uint)RedLow | (ulong)RedHigh << 32; ulong GreenCh = (uint)GreenLow | (ulong)GreenHigh << 32; diff --git a/Ryujinx.Graphics/Gpu/SwizzleAddr.cs b/Ryujinx.Graphics/Gal/Texture/SwizzleAddr.cs similarity index 98% rename from Ryujinx.Graphics/Gpu/SwizzleAddr.cs rename to Ryujinx.Graphics/Gal/Texture/SwizzleAddr.cs index 08e61eb58f..b67b841bcc 100644 --- a/Ryujinx.Graphics/Gpu/SwizzleAddr.cs +++ b/Ryujinx.Graphics/Gal/Texture/SwizzleAddr.cs @@ -1,6 +1,6 @@ using System; -namespace Ryujinx.Graphics.Gpu +namespace Ryujinx.Graphics.Gal.Texture { class SwizzleAddr { @@ -109,7 +109,7 @@ namespace Ryujinx.Graphics.Gpu * y x x x x x x y y y y x y y x y 0 0 0 0 1024 x 1024 dxt5 * y y x x x x x x y y y y x y y x y x 0 0 0 2048 x 2048 dxt1 * y y y x x x x x x y y y y x y y x y x x 0 0 1024 x 1024 rgba8888 - * + * * Read from right to left, LSB first. */ int XCnt = XBase; diff --git a/Ryujinx.Graphics/Gal/Texture/TextureDecoder.cs b/Ryujinx.Graphics/Gal/Texture/TextureDecoder.cs new file mode 100644 index 0000000000..4e50db51dd --- /dev/null +++ b/Ryujinx.Graphics/Gal/Texture/TextureDecoder.cs @@ -0,0 +1,19 @@ +using System; + +namespace Ryujinx.Graphics.Gal.Texture +{ + static class TextureDecoder + { + public static byte[] Decode(GalTexture Texture) + { + switch (Texture.Format) + { + case GalTextureFormat.BC1: return BCn.DecodeBC1(Texture, 0); + case GalTextureFormat.BC2: return BCn.DecodeBC2(Texture, 0); + case GalTextureFormat.BC3: return BCn.DecodeBC3(Texture, 0); + } + + throw new NotImplementedException(Texture.Format.ToString()); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gpu/NsGpuTexture.cs b/Ryujinx.Graphics/Gpu/NsGpuTexture.cs deleted file mode 100644 index aac4220059..0000000000 --- a/Ryujinx.Graphics/Gpu/NsGpuTexture.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Ryujinx.Graphics.Gpu -{ - struct NsGpuTexture - { - public int Width; - public int Height; - - public byte[] Data; - } -} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gpu/NsGpuTextureFormat.cs b/Ryujinx.Graphics/Gpu/NsGpuTextureFormat.cs deleted file mode 100644 index 2993840be7..0000000000 --- a/Ryujinx.Graphics/Gpu/NsGpuTextureFormat.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ryujinx.Graphics.Gpu -{ - enum NsGpuTextureFormat - { - BC1 = 0x24, - BC2 = 0x25, - BC3 = 0x26 - } -} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gpu/NvGpuEngine3d.cs b/Ryujinx.Graphics/Gpu/NvGpuEngine3d.cs index 21b2ae70d5..26664acefa 100644 --- a/Ryujinx.Graphics/Gpu/NvGpuEngine3d.cs +++ b/Ryujinx.Graphics/Gpu/NvGpuEngine3d.cs @@ -71,6 +71,7 @@ namespace Ryujinx.Graphics.Gpu Gpu.Renderer.BindProgram(); + UploadTextures(Memory); UploadUniforms(Memory); UploadVertexArrays(Memory); } @@ -95,7 +96,10 @@ namespace Ryujinx.Graphics.Gpu int Control = ReadRegister(NvGpuEngine3dReg.ShaderNControl + Index * 0x10); int Offset = ReadRegister(NvGpuEngine3dReg.ShaderNOffset + Index * 0x10); - if (Offset == 0 || (Index != 1 && Index != 5)) + //Note: Vertex Program (B) is always enabled. + bool Enable = (Control & 1) != 0 || Index == 1; + + if (!Enable) { continue; } @@ -104,11 +108,6 @@ namespace Ryujinx.Graphics.Gpu long Position = Gpu.GetCpuAddr(Tag); - if (Position == -1) - { - continue; - } - //TODO: Find a better way to calculate the size. int Size = 0x20000; @@ -127,11 +126,13 @@ namespace Ryujinx.Graphics.Gpu for (int Index = 0; Index < 5; Index++) { - int Offset = ReadRegister(NvGpuEngine3dReg.ShaderNOffset + (Index + 1) * 0x10); + int Control = ReadRegister(NvGpuEngine3dReg.ShaderNControl + (Index + 1) * 0x10); + int Offset = ReadRegister(NvGpuEngine3dReg.ShaderNOffset + (Index + 1) * 0x10); - long Tag = BasePosition + (uint)Offset; + //Note: Vertex Program (B) is always enabled. + bool Enable = (Control & 1) != 0 || Index == 0; - if (Offset == 0 || (Index != 0 && Index != 4)) + if (!Enable) { continue; } @@ -146,7 +147,7 @@ namespace Ryujinx.Graphics.Gpu byte[] Data = AMemoryHelper.ReadBytes(Memory, CbPosition, (uint)Cb.Size); - Gpu.Renderer.SetShaderCb(Tag, Cbuf, Data); + Gpu.Renderer.SetShaderConstBuffer(BasePosition + (uint)Offset, Cbuf, Data); } } } @@ -204,6 +205,78 @@ namespace Ryujinx.Graphics.Gpu } } + private void UploadTextures(AMemory Memory) + { + int TextureCbIndex = ReadRegister(NvGpuEngine3dReg.TextureCbIndex); + + long BasePosition = Cbs[TextureCbIndex].Position; + + long Size = (uint)Cbs[TextureCbIndex].Size; + + Gpu.Renderer.UpdateTextures((int Index, GalShaderType ShaderType) => + { + long Position = BasePosition + (int)ShaderType * Size; + + return TextureRequestHandler(Memory, Position, Index); + }); + } + + private GalTexture TextureRequestHandler(AMemory Memory, long BasePosition, int Index) + { + long Position = BasePosition + Index * 4; + + int TextureHandle = Memory.ReadInt32(Position); + + int TicIndex = (TextureHandle >> 0) & 0xfffff; + int TscIndex = (TextureHandle >> 20) & 0xfff; + + TryGetCpuAddr(NvGpuEngine3dReg.TexHeaderPoolOffset, out long TicPosition); + + int[] Tic = ReadWords(Memory, TicPosition + TicIndex * 0x20, 8); + + GalTextureFormat Format = (GalTextureFormat)(Tic[0] & 0x7f); + + long TextureAddress = (uint)Tic[1]; + + TextureAddress |= (long)((ushort)Tic[2]) << 32; + + TextureAddress = Gpu.GetCpuAddr(TextureAddress); + + int Width = (Tic[4] & 0xffff) + 1; + int Height = (Tic[5] & 0xffff) + 1; + + long TextureSize = GetTextureSize(Width, Height, Format); + + byte[] Data = AMemoryHelper.ReadBytes(Memory, TextureAddress, TextureSize); + + return new GalTexture(Data, Width, Height, Format); + } + + private long GetTextureSize(int Width, int Height, GalTextureFormat Format) + { + switch (Format) + { + case GalTextureFormat.A8B8G8R8: return (Width * Height) << 2; + case GalTextureFormat.BC1: return (Width * Height) >> 1; + case GalTextureFormat.BC2: return Width * Height; + case GalTextureFormat.BC3: return Width * Height; + } + + throw new NotImplementedException(Format.ToString()); + } + + private int[] ReadWords(AMemory Memory, long Position, int Count) + { + int[] Words = new int[Count]; + + for (int Index = 0; Index < Count; Index++, Position += 4) + { + Words[Index] = Memory.ReadInt32(Position); + } + + return Words; + } + private static GalShaderType GetTypeFromProgram(int Program) { switch (Program) @@ -267,7 +340,8 @@ namespace Ryujinx.Graphics.Gpu { Cbs[Index].Position = Position; Cbs[Index].Enabled = Enabled; - Cbs[Index].Size = ReadRegister(NvGpuEngine3dReg.ConstBufferNSize); + + Cbs[Index].Size = ReadRegister(NvGpuEngine3dReg.ConstBufferNSize); } } diff --git a/Ryujinx.Graphics/Gpu/NvGpuEngine3dReg.cs b/Ryujinx.Graphics/Gpu/NvGpuEngine3dReg.cs index ca6fd56dd6..db7496e0e7 100644 --- a/Ryujinx.Graphics/Gpu/NvGpuEngine3dReg.cs +++ b/Ryujinx.Graphics/Gpu/NvGpuEngine3dReg.cs @@ -3,6 +3,7 @@ namespace Ryujinx.Graphics.Gpu enum NvGpuEngine3dReg { VertexAttribNFormat = 0x458, + TexHeaderPoolOffset = 0x55d, ShaderAddress = 0x582, QueryAddress = 0x6c0, QuerySequence = 0x6c2, diff --git a/Ryujinx.Graphics/Gpu/NvGpuFifo.cs b/Ryujinx.Graphics/Gpu/NvGpuFifo.cs index df765895c4..0ae499b4db 100644 --- a/Ryujinx.Graphics/Gpu/NvGpuFifo.cs +++ b/Ryujinx.Graphics/Gpu/NvGpuFifo.cs @@ -141,6 +141,11 @@ namespace Ryujinx.Graphics.Gpu { case NvGpuEngine._3d: Call3dMethod(Memory, PBEntry); break; } + + if (PBEntry.SubChannel > 4) + { + throw new System.Exception("bad subch"); + } } }