diff --git a/Ryujinx.Core/OsHle/Services/Nv/INvDrvServices.cs b/Ryujinx.Core/OsHle/Services/Nv/INvDrvServices.cs index f41a98d0..2652724d 100644 --- a/Ryujinx.Core/OsHle/Services/Nv/INvDrvServices.cs +++ b/Ryujinx.Core/OsHle/Services/Nv/INvDrvServices.cs @@ -51,6 +51,8 @@ namespace Ryujinx.Core.OsHle.Services.Nv { ("/dev/nvhost-as-gpu", 0x4114), NvGpuAsIoctlRemap }, { ("/dev/nvhost-ctrl", 0x001b), NvHostIoctlCtrlGetConfig }, { ("/dev/nvhost-ctrl", 0x001d), NvHostIoctlCtrlEventWait }, + { ("/dev/nvhost-ctrl", 0x001e), NvHostIoctlCtrlEventWaitAsync }, + { ("/dev/nvhost-ctrl", 0x001f), NvHostIoctlCtrlEventRegister }, { ("/dev/nvhost-ctrl-gpu", 0x4701), NvGpuIoctlZcullGetCtxSize }, { ("/dev/nvhost-ctrl-gpu", 0x4702), NvGpuIoctlZcullGetInfo }, { ("/dev/nvhost-ctrl-gpu", 0x4703), NvGpuIoctlZbcSetTable }, @@ -384,6 +386,33 @@ namespace Ryujinx.Core.OsHle.Services.Nv return 0; } + private long NvHostIoctlCtrlEventWaitAsync(ServiceCtx Context) + { + long Position = Context.Request.GetSendBuffPtr(); + + MemReader Reader = new MemReader(Context.Memory, Position); + + int SyncPtId = Reader.ReadInt32(); + int Threshold = Reader.ReadInt32(); + int Timeout = Reader.ReadInt32(); + int Value = Reader.ReadInt32(); + + Context.Memory.WriteInt32(Position + 0xc, 0xcafe); + + return 0; + } + + private long NvHostIoctlCtrlEventRegister(ServiceCtx Context) + { + long Position = Context.Request.GetSendBuffPtr(); + + MemReader Reader = new MemReader(Context.Memory, Position); + + int UserEventId = Reader.ReadInt32(); + + return 0; + } + private long NvGpuIoctlZcullGetCtxSize(ServiceCtx Context) { long Position = Context.Request.GetSendBuffPtr(); diff --git a/Ryujinx.Graphics/Gal/GalVertexAttrib.cs b/Ryujinx.Graphics/Gal/GalVertexAttrib.cs index 563e624d..dd040060 100644 --- a/Ryujinx.Graphics/Gal/GalVertexAttrib.cs +++ b/Ryujinx.Graphics/Gal/GalVertexAttrib.cs @@ -2,6 +2,7 @@ namespace Ryujinx.Graphics.Gal { public struct GalVertexAttrib { + public int Index { get; private set; } public bool IsConst { get; private set; } public int Offset { get; private set; } @@ -11,12 +12,14 @@ namespace Ryujinx.Graphics.Gal public bool IsBgra { get; private set; } public GalVertexAttrib( + int Index, bool IsConst, int Offset, GalVertexAttribSize Size, GalVertexAttribType Type, bool IsBgra) { + this.Index = Index; this.IsConst = IsConst; this.Offset = Offset; this.Size = Size; diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLRasterizer.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLRasterizer.cs index b1504563..5b115446 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLRasterizer.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLRasterizer.cs @@ -44,12 +44,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL { GalVertexAttribSize._11_11_10, VertexAttribPointerType.Int } //? }; - private struct VbInfo - { - public int VaoHandle; - public int VboHandle; - } - private struct IbInfo { public int IboHandle; @@ -58,13 +52,15 @@ namespace Ryujinx.Graphics.Gal.OpenGL public DrawElementsType Type; } - private VbInfo[] VertexBuffers; + private int VaoHandle; + + private int[] VertexBuffers; private IbInfo IndexBuffer; public OGLRasterizer() { - VertexBuffers = new VbInfo[32]; + VertexBuffers = new int[32]; IndexBuffer = new IbInfo(); } @@ -100,28 +96,19 @@ namespace Ryujinx.Graphics.Gal.OpenGL { EnsureVbInitialized(VbIndex); - VbInfo Vb = VertexBuffers[VbIndex]; - IntPtr Length = new IntPtr(Buffer.Length); - GL.BindBuffer(BufferTarget.ArrayBuffer, Vb.VboHandle); + GL.BindBuffer(BufferTarget.ArrayBuffer, VertexBuffers[VbIndex]); GL.BufferData(BufferTarget.ArrayBuffer, Length, Buffer, BufferUsageHint.StreamDraw); GL.BindBuffer(BufferTarget.ArrayBuffer, 0); - GL.BindVertexArray(Vb.VaoHandle); + GL.BindVertexArray(VaoHandle); - for (int Attr = 0; Attr < 16; Attr++) + foreach (GalVertexAttrib Attrib in Attribs) { - GL.DisableVertexAttribArray(Attr); - } + GL.EnableVertexAttribArray(Attrib.Index); - for (int Index = 0; Index < Attribs.Length; Index++) - { - GalVertexAttrib Attrib = Attribs[Index]; - - GL.EnableVertexAttribArray(Index); - - GL.BindBuffer(BufferTarget.ArrayBuffer, Vb.VboHandle); + GL.BindBuffer(BufferTarget.ArrayBuffer, VertexBuffers[VbIndex]); bool Unsigned = Attrib.Type == GalVertexAttribType.Unorm || @@ -146,7 +133,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL int Size = AttribElements[Attrib.Size]; int Offset = Attrib.Offset; - GL.VertexAttribPointer(Index, Size, Type, Normalize, Stride, Offset); + GL.VertexAttribPointer(Attrib.Index, Size, Type, Normalize, Stride, Offset); } GL.BindVertexArray(0); @@ -174,20 +161,16 @@ namespace Ryujinx.Graphics.Gal.OpenGL return; } - VbInfo Vb = VertexBuffers[VbIndex]; - - GL.BindVertexArray(Vb.VaoHandle); + GL.BindVertexArray(VaoHandle); GL.DrawArrays(OGLEnumConverter.GetPrimitiveType(PrimType), First, PrimCount); } public void DrawElements(int VbIndex, int First, GalPrimitiveType PrimType) { - VbInfo Vb = VertexBuffers[VbIndex]; - PrimitiveType Mode = OGLEnumConverter.GetPrimitiveType(PrimType); - GL.BindVertexArray(Vb.VaoHandle); + GL.BindVertexArray(VaoHandle); GL.BindBuffer(BufferTarget.ElementArrayBuffer, IndexBuffer.IboHandle); @@ -196,19 +179,15 @@ namespace Ryujinx.Graphics.Gal.OpenGL private void EnsureVbInitialized(int VbIndex) { - VbInfo Vb = VertexBuffers[VbIndex]; - - if (Vb.VaoHandle == 0) + if (VaoHandle == 0) { - Vb.VaoHandle = GL.GenVertexArray(); + VaoHandle = GL.GenVertexArray(); } - if (Vb.VboHandle == 0) + if (VertexBuffers[VbIndex] == 0) { - Vb.VboHandle = GL.GenBuffer(); + VertexBuffers[VbIndex] = GL.GenBuffer(); } - - VertexBuffers[VbIndex] = Vb; } private void EnsureIbInitialized() diff --git a/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs b/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs index c22f5926..1e0824d2 100644 --- a/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs +++ b/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs @@ -261,13 +261,16 @@ namespace Ryujinx.Graphics.Gal.Shader PrintBlockScope(SubScopeName, IdentationLevel + 1, Cond.Child); } - else if (Node is ShaderIrAsg Asg && IsValidOutOper(Asg.Dst)) + else if (Node is ShaderIrAsg Asg) { - string Expr = GetSrcExpr(Asg.Src, true); + if (IsValidOutOper(Asg.Dst)) + { + string Expr = GetSrcExpr(Asg.Src, true); - Expr = GetExprWithCast(Asg.Dst, Asg.Src, Expr); + Expr = GetExprWithCast(Asg.Dst, Asg.Src, Expr); - SB.AppendLine(Identation + GetDstOperName(Asg.Dst) + " = " + Expr + ";"); + SB.AppendLine(Identation + GetDstOperName(Asg.Dst) + " = " + Expr + ";"); + } } else if (Node is ShaderIrOp Op) { diff --git a/Ryujinx.Graphics/Gpu/NvGpuEngine3d.cs b/Ryujinx.Graphics/Gpu/NvGpuEngine3d.cs index bf04db36..a6696650 100644 --- a/Ryujinx.Graphics/Gpu/NvGpuEngine3d.cs +++ b/Ryujinx.Graphics/Gpu/NvGpuEngine3d.cs @@ -351,6 +351,7 @@ namespace Ryujinx.Graphics.Gpu } Attribs[ArrayIndex].Add(new GalVertexAttrib( + Attr, ((Packed >> 6) & 0x1) != 0, (Packed >> 7) & 0x3fff, (GalVertexAttribSize)((Packed >> 21) & 0x3f), @@ -367,18 +368,34 @@ namespace Ryujinx.Graphics.Gpu bool Enable = (Control & 0x1000) != 0; + long VertexPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.VertexArrayNAddress + Index * 4); + if (!Enable) { continue; } - long VertexPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.VertexArrayNAddress + Index * 4); - long VertexEndPos = MakeInt64From2xInt32(NvGpuEngine3dReg.VertexArrayNEndAddr + Index * 4); - - long Size = (VertexEndPos - VertexPosition) + 1; - int Stride = Control & 0xfff; + long Size = 0; + + if (IndexCount != 0) + { + Size = GetVertexCountFromIndexBuffer( + Memory, + IndexPosition, + IndexCount, + IndexSize); + } + else + { + Size = VertexCount; + } + + //TODO: Support cases where the Stride is 0. + //In this case, we need to use the size of the attribute. + Size *= Stride; + VertexPosition = Gpu.GetCpuAddr(VertexPosition); byte[] Data = AMemoryHelper.ReadBytes(Memory, VertexPosition, Size); @@ -402,6 +419,62 @@ namespace Ryujinx.Graphics.Gpu } } + private int GetVertexCountFromIndexBuffer( + AMemory Memory, + long IndexPosition, + int IndexCount, + int IndexSize) + { + int MaxIndex = -1; + + if (IndexSize == 2) + { + while (IndexCount -- > 0) + { + ushort Value = Memory.ReadUInt16(IndexPosition); + + IndexPosition += 2; + + if (MaxIndex < Value) + { + MaxIndex = Value; + } + } + } + else if (IndexSize == 1) + { + while (IndexCount -- > 0) + { + byte Value = Memory.ReadByte(IndexPosition++); + + if (MaxIndex < Value) + { + MaxIndex = Value; + } + } + } + else if (IndexSize == 4) + { + while (IndexCount -- > 0) + { + uint Value = Memory.ReadUInt32(IndexPosition); + + IndexPosition += 2; + + if (MaxIndex < Value) + { + MaxIndex = (int)Value; + } + } + } + else + { + throw new ArgumentOutOfRangeException(nameof(IndexSize)); + } + + return MaxIndex + 1; + } + private void QueryControl(AMemory Memory, NsGpuPBEntry PBEntry) { if (TryGetCpuAddr(NvGpuEngine3dReg.QueryAddress, out long Position))