diff --git a/ChocolArm64/Memory/AMemory.cs b/ChocolArm64/Memory/AMemory.cs index d7e11189f6..6625966f1a 100644 --- a/ChocolArm64/Memory/AMemory.cs +++ b/ChocolArm64/Memory/AMemory.cs @@ -6,7 +6,7 @@ using System.Runtime.InteropServices; namespace ChocolArm64.Memory { - public unsafe class AMemory : IDisposable + public unsafe class AMemory : IAMemory, IDisposable { private const long ErgMask = (4 << AThreadState.ErgSizeLog2) - 1; diff --git a/ChocolArm64/Memory/IAMemory.cs b/ChocolArm64/Memory/IAMemory.cs new file mode 100644 index 0000000000..5b7d17bb8b --- /dev/null +++ b/ChocolArm64/Memory/IAMemory.cs @@ -0,0 +1,37 @@ +namespace ChocolArm64.Memory +{ + public interface IAMemory + { + sbyte ReadSByte(long Position); + + short ReadInt16(long Position); + + int ReadInt32(long Position); + + long ReadInt64(long Position); + + byte ReadByte(long Position); + + ushort ReadUInt16(long Position); + + uint ReadUInt32(long Position); + + ulong ReadUInt64(long Position); + + void WriteSByte(long Position, sbyte Value); + + void WriteInt16(long Position, short Value); + + void WriteInt32(long Position, int Value); + + void WriteInt64(long Position, long Value); + + void WriteByte(long Position, byte Value); + + void WriteUInt16(long Position, ushort Value); + + void WriteUInt32(long Position, uint Value); + + void WriteUInt64(long Position, ulong Value); + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gpu/BlockLinearSwizzle.cs b/Ryujinx.Core/Gpu/BlockLinearSwizzle.cs similarity index 97% rename from Ryujinx.Graphics/Gpu/BlockLinearSwizzle.cs rename to Ryujinx.Core/Gpu/BlockLinearSwizzle.cs index d2cbb14432..eb41ea3001 100644 --- a/Ryujinx.Graphics/Gpu/BlockLinearSwizzle.cs +++ b/Ryujinx.Core/Gpu/BlockLinearSwizzle.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.Graphics.Gpu +namespace Ryujinx.Core.Gpu { class BlockLinearSwizzle : ISwizzle { diff --git a/Ryujinx.Core/Gpu/INvGpuEngine.cs b/Ryujinx.Core/Gpu/INvGpuEngine.cs new file mode 100644 index 0000000000..865ea8ba89 --- /dev/null +++ b/Ryujinx.Core/Gpu/INvGpuEngine.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.Core.Gpu +{ + interface INvGpuEngine + { + int[] Registers { get; } + + void CallMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry); + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gpu/ISwizzle.cs b/Ryujinx.Core/Gpu/ISwizzle.cs similarity index 72% rename from Ryujinx.Graphics/Gpu/ISwizzle.cs rename to Ryujinx.Core/Gpu/ISwizzle.cs index 755051d0c4..f475be6efc 100644 --- a/Ryujinx.Graphics/Gpu/ISwizzle.cs +++ b/Ryujinx.Core/Gpu/ISwizzle.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.Graphics.Gpu +namespace Ryujinx.Core.Gpu { interface ISwizzle { diff --git a/Ryujinx.Graphics/Gpu/LinearSwizzle.cs b/Ryujinx.Core/Gpu/LinearSwizzle.cs similarity index 91% rename from Ryujinx.Graphics/Gpu/LinearSwizzle.cs rename to Ryujinx.Core/Gpu/LinearSwizzle.cs index c7a6b304e8..5f8dfddee5 100644 --- a/Ryujinx.Graphics/Gpu/LinearSwizzle.cs +++ b/Ryujinx.Core/Gpu/LinearSwizzle.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.Graphics.Gpu +namespace Ryujinx.Core.Gpu { class LinearSwizzle : ISwizzle { diff --git a/Ryujinx.Graphics/Gpu/MacroInterpreter.cs b/Ryujinx.Core/Gpu/MacroInterpreter.cs similarity index 92% rename from Ryujinx.Graphics/Gpu/MacroInterpreter.cs rename to Ryujinx.Core/Gpu/MacroInterpreter.cs index 233baac8bd..b799f98fa6 100644 --- a/Ryujinx.Graphics/Gpu/MacroInterpreter.cs +++ b/Ryujinx.Core/Gpu/MacroInterpreter.cs @@ -1,8 +1,7 @@ -using ChocolArm64.Memory; using System; using System.Collections.Generic; -namespace Ryujinx.Graphics.Gpu +namespace Ryujinx.Core.Gpu { class MacroInterpreter { @@ -69,7 +68,7 @@ namespace Ryujinx.Graphics.Gpu Gprs = new int[8]; } - public void Execute(AMemory Memory, long Position, int Param) + public void Execute(NvGpuVmm Vmm, long Position, int Param) { Reset(); @@ -77,13 +76,13 @@ namespace Ryujinx.Graphics.Gpu Pc = Position; - FetchOpCode(Memory); + FetchOpCode(Vmm); - while (Step(Memory)); + while (Step(Vmm)); //Due to the delay slot, we still need to execute //one more instruction before we actually exit. - Step(Memory); + Step(Vmm); } private void Reset() @@ -99,11 +98,11 @@ namespace Ryujinx.Graphics.Gpu Carry = false; } - private bool Step(AMemory Memory) + private bool Step(NvGpuVmm Vmm) { long BaseAddr = Pc - 4; - FetchOpCode(Memory); + FetchOpCode(Vmm); if ((OpCode & 7) < 7) { @@ -145,7 +144,7 @@ namespace Ryujinx.Graphics.Gpu { SetDstGpr(FetchParam()); - Send(Memory, Result); + Send(Vmm, Result); break; } @@ -155,7 +154,7 @@ namespace Ryujinx.Graphics.Gpu { SetDstGpr(Result); - Send(Memory, Result); + Send(Vmm, Result); break; } @@ -177,7 +176,7 @@ namespace Ryujinx.Graphics.Gpu SetMethAddr(Result); - Send(Memory, FetchParam()); + Send(Vmm, FetchParam()); break; } @@ -189,7 +188,7 @@ namespace Ryujinx.Graphics.Gpu SetMethAddr(Result); - Send(Memory, (Result >> 12) & 0x3f); + Send(Vmm, (Result >> 12) & 0x3f); break; } @@ -212,7 +211,7 @@ namespace Ryujinx.Graphics.Gpu if (NoDelays) { - FetchOpCode(Memory); + FetchOpCode(Vmm); } return true; @@ -224,11 +223,11 @@ namespace Ryujinx.Graphics.Gpu return !Exit; } - private void FetchOpCode(AMemory Memory) + private void FetchOpCode(NvGpuVmm Vmm) { OpCode = PipeOp; - PipeOp = Memory.ReadInt32(Pc); + PipeOp = Vmm.ReadInt32(Pc); Pc += 4; } @@ -408,11 +407,11 @@ namespace Ryujinx.Graphics.Gpu return Engine.Registers[Reg]; } - private void Send(AMemory Memory, int Value) + private void Send(NvGpuVmm Vmm, int Value) { - NsGpuPBEntry PBEntry = new NsGpuPBEntry(MethAddr, 0, Value); + NvGpuPBEntry PBEntry = new NvGpuPBEntry(MethAddr, 0, Value); - Engine.CallMethod(Memory, PBEntry); + Engine.CallMethod(Vmm, PBEntry); MethAddr += MethIncr; } diff --git a/Ryujinx.Graphics/Gpu/NsGpu.cs b/Ryujinx.Core/Gpu/NvGpu.cs similarity index 50% rename from Ryujinx.Graphics/Gpu/NsGpu.cs rename to Ryujinx.Core/Gpu/NvGpu.cs index e10889821e..71df76ff31 100644 --- a/Ryujinx.Graphics/Gpu/NsGpu.cs +++ b/Ryujinx.Core/Gpu/NvGpu.cs @@ -1,14 +1,12 @@ using Ryujinx.Graphics.Gal; using System.Threading; -namespace Ryujinx.Graphics.Gpu +namespace Ryujinx.Core.Gpu { - public class NsGpu + public class NvGpu { public IGalRenderer Renderer { get; private set; } - public NsGpuMemoryMgr MemoryMgr { get; private set; } - public NvGpuFifo Fifo { get; private set; } public NvGpuEngine2d Engine2d { get; private set; } @@ -18,12 +16,10 @@ namespace Ryujinx.Graphics.Gpu private bool KeepRunning; - public NsGpu(IGalRenderer Renderer) + public NvGpu(IGalRenderer Renderer) { this.Renderer = Renderer; - MemoryMgr = new NsGpuMemoryMgr(); - Fifo = new NvGpuFifo(this); Engine2d = new NvGpuEngine2d(this); @@ -36,31 +32,6 @@ namespace Ryujinx.Graphics.Gpu FifoProcessing.Start(); } - public long GetCpuAddr(long Position) - { - return MemoryMgr.GetCpuAddr(Position); - } - - public long MapMemory(long CpuAddr, long Size) - { - return MemoryMgr.Map(CpuAddr, Size); - } - - public long MapMemory(long CpuAddr, long GpuAddr, long Size) - { - return MemoryMgr.Map(CpuAddr, GpuAddr, Size); - } - - public long ReserveMemory(long Size, long Align) - { - return MemoryMgr.Reserve(Size, Align); - } - - public long ReserveMemory(long GpuAddr, long Size, long Align) - { - return MemoryMgr.Reserve(GpuAddr, Size, Align); - } - private void ProcessFifo() { while (KeepRunning) diff --git a/Ryujinx.Graphics/Gpu/NvGpuEngine.cs b/Ryujinx.Core/Gpu/NvGpuEngine.cs similarity index 84% rename from Ryujinx.Graphics/Gpu/NvGpuEngine.cs rename to Ryujinx.Core/Gpu/NvGpuEngine.cs index 624915d0d4..ee0420f704 100644 --- a/Ryujinx.Graphics/Gpu/NvGpuEngine.cs +++ b/Ryujinx.Core/Gpu/NvGpuEngine.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.Graphics.Gpu +namespace Ryujinx.Core.Gpu { enum NvGpuEngine { diff --git a/Ryujinx.Graphics/Gpu/NvGpuEngine2d.cs b/Ryujinx.Core/Gpu/NvGpuEngine2d.cs similarity index 74% rename from Ryujinx.Graphics/Gpu/NvGpuEngine2d.cs rename to Ryujinx.Core/Gpu/NvGpuEngine2d.cs index c2bee167d8..e18b73a668 100644 --- a/Ryujinx.Graphics/Gpu/NvGpuEngine2d.cs +++ b/Ryujinx.Core/Gpu/NvGpuEngine2d.cs @@ -1,8 +1,7 @@ -using ChocolArm64.Memory; using Ryujinx.Graphics.Gal; using System.Collections.Generic; -namespace Ryujinx.Graphics.Gpu +namespace Ryujinx.Core.Gpu { public class NvGpuEngine2d : INvGpuEngine { @@ -19,11 +18,11 @@ namespace Ryujinx.Graphics.Gpu public int[] Registers { get; private set; } - private NsGpu Gpu; + private NvGpu Gpu; private Dictionary Methods; - public NvGpuEngine2d(NsGpu Gpu) + public NvGpuEngine2d(NvGpu Gpu) { this.Gpu = Gpu; @@ -44,11 +43,11 @@ namespace Ryujinx.Graphics.Gpu AddMethod(0xb5, 1, 1, TextureCopy); } - public void CallMethod(AMemory Memory, NsGpuPBEntry PBEntry) + public void CallMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry) { if (Methods.TryGetValue(PBEntry.Method, out NvGpuMethod Method)) { - Method(Memory, PBEntry); + Method(Vmm, PBEntry); } else { @@ -56,7 +55,7 @@ namespace Ryujinx.Graphics.Gpu } } - private void TextureCopy(AMemory Memory, NsGpuPBEntry PBEntry) + private void TextureCopy(NvGpuVmm Vmm, NvGpuPBEntry PBEntry) { CopyOperation Operation = (CopyOperation)ReadRegister(NvGpuEngine2dReg.CopyOperation); @@ -76,10 +75,10 @@ namespace Ryujinx.Graphics.Gpu int DstBlockHeight = 1 << ((DstBlkDim >> 4) & 0xf); - long Tag = MakeInt64From2xInt32(NvGpuEngine2dReg.SrcAddress); + long Tag = Vmm.GetCpuAddr(MakeInt64From2xInt32(NvGpuEngine2dReg.SrcAddress)); - TryGetCpuAddr(NvGpuEngine2dReg.SrcAddress, out long SrcAddress); - TryGetCpuAddr(NvGpuEngine2dReg.DstAddress, out long DstAddress); + long SrcAddress = MakeInt64From2xInt32(NvGpuEngine2dReg.SrcAddress); + long DstAddress = MakeInt64From2xInt32(NvGpuEngine2dReg.DstAddress); bool IsFbTexture = Gpu.Engine3d.IsFrameBufferPosition(Tag); @@ -101,31 +100,22 @@ namespace Ryujinx.Graphics.Gpu { Gpu.Renderer.GetFrameBufferData(Tag, (byte[] Buffer) => { - CopyTexture(Memory, DstTexture, Buffer); + CopyTexture(Vmm, DstTexture, Buffer); }); } else { long Size = SrcWidth * SrcHeight * 4; - byte[] Buffer = AMemoryHelper.ReadBytes(Memory, SrcAddress, Size); + byte[] Buffer = Vmm.ReadBytes(SrcAddress, Size); - CopyTexture(Memory, DstTexture, Buffer); + CopyTexture(Vmm, DstTexture, Buffer); } } - private void CopyTexture(AMemory Memory, Texture Texture, byte[] Buffer) + private void CopyTexture(NvGpuVmm Vmm, Texture Texture, byte[] Buffer) { - TextureWriter.Write(Memory, Texture, Buffer); - } - - private bool TryGetCpuAddr(NvGpuEngine2dReg Reg, out long Position) - { - Position = MakeInt64From2xInt32(Reg); - - Position = Gpu.GetCpuAddr(Position); - - return Position != -1; + TextureWriter.Write(Vmm, Texture, Buffer); } private long MakeInt64From2xInt32(NvGpuEngine2dReg Reg) @@ -135,7 +125,7 @@ namespace Ryujinx.Graphics.Gpu (uint)Registers[(int)Reg + 1]; } - private void WriteRegister(NsGpuPBEntry PBEntry) + private void WriteRegister(NvGpuPBEntry PBEntry) { int ArgsCount = PBEntry.Arguments.Count; diff --git a/Ryujinx.Graphics/Gpu/NvGpuEngine2dReg.cs b/Ryujinx.Core/Gpu/NvGpuEngine2dReg.cs similarity index 95% rename from Ryujinx.Graphics/Gpu/NvGpuEngine2dReg.cs rename to Ryujinx.Core/Gpu/NvGpuEngine2dReg.cs index 903baca87c..b4abad00da 100644 --- a/Ryujinx.Graphics/Gpu/NvGpuEngine2dReg.cs +++ b/Ryujinx.Core/Gpu/NvGpuEngine2dReg.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.Graphics.Gpu +namespace Ryujinx.Core.Gpu { enum NvGpuEngine2dReg { diff --git a/Ryujinx.Graphics/Gpu/NvGpuEngine3d.cs b/Ryujinx.Core/Gpu/NvGpuEngine3d.cs similarity index 73% rename from Ryujinx.Graphics/Gpu/NvGpuEngine3d.cs rename to Ryujinx.Core/Gpu/NvGpuEngine3d.cs index a6696650b6..422ac4d965 100644 --- a/Ryujinx.Graphics/Gpu/NvGpuEngine3d.cs +++ b/Ryujinx.Core/Gpu/NvGpuEngine3d.cs @@ -1,15 +1,14 @@ -using ChocolArm64.Memory; using Ryujinx.Graphics.Gal; using System; using System.Collections.Generic; -namespace Ryujinx.Graphics.Gpu +namespace Ryujinx.Core.Gpu { public class NvGpuEngine3d : INvGpuEngine { public int[] Registers { get; private set; } - private NsGpu Gpu; + private NvGpu Gpu; private Dictionary Methods; @@ -20,11 +19,11 @@ namespace Ryujinx.Graphics.Gpu public int Size; } - private ConstBuffer[] ConstBuffers; + private ConstBuffer[][] ConstBuffers; private HashSet FrameBuffers; - public NvGpuEngine3d(NsGpu Gpu) + public NvGpuEngine3d(NvGpu Gpu) { this.Gpu = Gpu; @@ -46,18 +45,23 @@ namespace Ryujinx.Graphics.Gpu AddMethod(0x674, 1, 1, ClearBuffers); AddMethod(0x6c3, 1, 1, QueryControl); AddMethod(0x8e4, 16, 1, CbData); - AddMethod(0x904, 1, 1, CbBind); + AddMethod(0x904, 5, 8, CbBind); - ConstBuffers = new ConstBuffer[18]; + ConstBuffers = new ConstBuffer[6][]; + + for (int Index = 0; Index < ConstBuffers.Length; Index++) + { + ConstBuffers[Index] = new ConstBuffer[18]; + } FrameBuffers = new HashSet(); } - public void CallMethod(AMemory Memory, NsGpuPBEntry PBEntry) + public void CallMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry) { if (Methods.TryGetValue(PBEntry.Method, out NvGpuMethod Method)) { - Method(Memory, PBEntry); + Method(Vmm, PBEntry); } else { @@ -65,22 +69,22 @@ namespace Ryujinx.Graphics.Gpu } } - private void VertexEndGl(AMemory Memory, NsGpuPBEntry PBEntry) + private void VertexEndGl(NvGpuVmm Vmm, NvGpuPBEntry PBEntry) { - SetFrameBuffer(0); + SetFrameBuffer(Vmm, 0); - long[] Tags = UploadShaders(Memory); + long[] Tags = UploadShaders(Vmm); Gpu.Renderer.BindProgram(); SetAlphaBlending(); - UploadTextures(Memory, Tags); - UploadUniforms(Memory); - UploadVertexArrays(Memory); + UploadTextures(Vmm, Tags); + UploadUniforms(Vmm); + UploadVertexArrays(Vmm); } - private void ClearBuffers(AMemory Memory, NsGpuPBEntry PBEntry) + private void ClearBuffers(NvGpuVmm Vmm, NvGpuPBEntry PBEntry) { int Arg0 = PBEntry.Arguments[0]; @@ -90,28 +94,30 @@ namespace Ryujinx.Graphics.Gpu GalClearBufferFlags Flags = (GalClearBufferFlags)(Arg0 & 0x3f); - SetFrameBuffer(0); + SetFrameBuffer(Vmm, 0); //TODO: Enable this once the frame buffer problems are fixed. //Gpu.Renderer.ClearBuffers(Layer, Flags); } - private void SetFrameBuffer(int FbIndex) + private void SetFrameBuffer(NvGpuVmm Vmm, int FbIndex) { - long Address = MakeInt64From2xInt32(NvGpuEngine3dReg.FrameBufferNAddress + FbIndex * 0x10); + long VA = MakeInt64From2xInt32(NvGpuEngine3dReg.FrameBufferNAddress + FbIndex * 0x10); - FrameBuffers.Add(Address); + long PA = Vmm.GetCpuAddr(VA); + + FrameBuffers.Add(PA); int Width = ReadRegister(NvGpuEngine3dReg.FrameBufferNWidth + FbIndex * 0x10); int Height = ReadRegister(NvGpuEngine3dReg.FrameBufferNHeight + FbIndex * 0x10); //Note: Using the Width/Height results seems to give incorrect results. //Maybe the size of all frame buffers is hardcoded to screen size? This seems unlikely. - Gpu.Renderer.CreateFrameBuffer(Address, 1280, 720); - Gpu.Renderer.BindFrameBuffer(Address); + Gpu.Renderer.CreateFrameBuffer(PA, 1280, 720); + Gpu.Renderer.BindFrameBuffer(PA); } - private long[] UploadShaders(AMemory Memory) + private long[] UploadShaders(NvGpuVmm Vmm) { long[] Tags = new long[5]; @@ -132,12 +138,10 @@ namespace Ryujinx.Graphics.Gpu long Tag = BasePosition + (uint)Offset; - long Position = Gpu.GetCpuAddr(Tag); - //TODO: Find a better way to calculate the size. int Size = 0x20000; - byte[] Code = AMemoryHelper.ReadBytes(Memory, Position, (uint)Size); + byte[] Code = Vmm.ReadBytes(Tag, Size); GalShaderType ShaderType = GetTypeFromProgram(Index); @@ -211,16 +215,12 @@ namespace Ryujinx.Graphics.Gpu } } - private void UploadTextures(AMemory Memory, long[] Tags) + private void UploadTextures(NvGpuVmm Vmm, long[] Tags) { long BaseShPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.ShaderAddress); int TextureCbIndex = ReadRegister(NvGpuEngine3dReg.TextureCbIndex); - long BasePosition = ConstBuffers[TextureCbIndex].Position; - - long Size = (uint)ConstBuffers[TextureCbIndex].Size; - //Note: On the emulator renderer, Texture Unit 0 is //reserved for drawing the frame buffer. int TexIndex = 1; @@ -229,9 +229,9 @@ namespace Ryujinx.Graphics.Gpu { foreach (ShaderDeclInfo DeclInfo in Gpu.Renderer.GetTextureUsage(Tags[Index])) { - long Position = BasePosition + Index * Size; + long Position = ConstBuffers[Index][TextureCbIndex].Position; - UploadTexture(Memory, Position, TexIndex, DeclInfo.Index); + UploadTexture(Vmm, Position, TexIndex, DeclInfo.Index); Gpu.Renderer.SetUniform1(DeclInfo.Name, TexIndex); @@ -240,26 +240,28 @@ namespace Ryujinx.Graphics.Gpu } } - private void UploadTexture(AMemory Memory, long BasePosition, int TexIndex, int HndIndex) + private void UploadTexture(NvGpuVmm Vmm, long BasePosition, int TexIndex, int HndIndex) { long Position = BasePosition + HndIndex * 4; - int TextureHandle = Memory.ReadInt32(Position); + int TextureHandle = Vmm.ReadInt32(Position); int TicIndex = (TextureHandle >> 0) & 0xfffff; int TscIndex = (TextureHandle >> 20) & 0xfff; - TryGetCpuAddr(NvGpuEngine3dReg.TexHeaderPoolOffset, out long TicPosition); - TryGetCpuAddr(NvGpuEngine3dReg.TexSamplerPoolOffset, out long TscPosition); + long TicPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.TexHeaderPoolOffset); + long TscPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.TexSamplerPoolOffset); TicPosition += TicIndex * 0x20; TscPosition += TscIndex * 0x20; - GalTextureSampler Sampler = TextureFactory.MakeSampler(Gpu, Memory, TscPosition); + GalTextureSampler Sampler = TextureFactory.MakeSampler(Gpu, Vmm, TscPosition); - long TextureAddress = Memory.ReadInt64(TicPosition + 4) & 0xffffffffffff; + long TextureAddress = Vmm.ReadInt64(TicPosition + 4) & 0xffffffffffff; - if (FrameBuffers.Contains(TextureAddress)) + TextureAddress = Vmm.GetCpuAddr(TextureAddress); + + if (IsFrameBufferPosition(TextureAddress)) { //This texture is a frame buffer texture, //we shouldn't read anything from memory and bind @@ -269,14 +271,14 @@ namespace Ryujinx.Graphics.Gpu } else { - GalTexture Texture = TextureFactory.MakeTexture(Gpu, Memory, TicPosition); + GalTexture Texture = TextureFactory.MakeTexture(Gpu, Vmm, TicPosition); Gpu.Renderer.SetTextureAndSampler(TexIndex, Texture, Sampler); Gpu.Renderer.BindTexture(TexIndex); } } - private void UploadUniforms(AMemory Memory) + private void UploadUniforms(NvGpuVmm Vmm) { long BasePosition = MakeInt64From2xInt32(NvGpuEngine3dReg.ShaderAddress); @@ -295,13 +297,11 @@ namespace Ryujinx.Graphics.Gpu for (int Cbuf = 0; Cbuf < ConstBuffers.Length; Cbuf++) { - ConstBuffer Cb = ConstBuffers[Cbuf]; + ConstBuffer Cb = ConstBuffers[Index][Cbuf]; if (Cb.Enabled) { - long CbPosition = Cb.Position + Index * Cb.Size; - - byte[] Data = AMemoryHelper.ReadBytes(Memory, CbPosition, (uint)Cb.Size); + byte[] Data = Vmm.ReadBytes(Cb.Position, (uint)Cb.Size); Gpu.Renderer.SetConstBuffer(BasePosition + (uint)Offset, Cbuf, Data); } @@ -309,7 +309,7 @@ namespace Ryujinx.Graphics.Gpu } } - private void UploadVertexArrays(AMemory Memory) + private void UploadVertexArrays(NvGpuVmm Vmm) { long IndexPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.IndexArrayAddress); @@ -328,11 +328,9 @@ namespace Ryujinx.Graphics.Gpu if (IndexSize != 0) { - IndexPosition = Gpu.GetCpuAddr(IndexPosition); - int BufferSize = IndexCount * IndexSize; - byte[] Data = AMemoryHelper.ReadBytes(Memory, IndexPosition, BufferSize); + byte[] Data = Vmm.ReadBytes(IndexPosition, BufferSize); Gpu.Renderer.SetIndexArray(Data, IndexFormat); } @@ -382,7 +380,7 @@ namespace Ryujinx.Graphics.Gpu if (IndexCount != 0) { Size = GetVertexCountFromIndexBuffer( - Memory, + Vmm, IndexPosition, IndexCount, IndexSize); @@ -396,9 +394,7 @@ namespace Ryujinx.Graphics.Gpu //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); + byte[] Data = Vmm.ReadBytes(VertexPosition, Size); GalVertexAttrib[] AttribArray = Attribs[Index]?.ToArray() ?? new GalVertexAttrib[0]; @@ -420,10 +416,10 @@ namespace Ryujinx.Graphics.Gpu } private int GetVertexCountFromIndexBuffer( - AMemory Memory, - long IndexPosition, - int IndexCount, - int IndexSize) + NvGpuVmm Vmm, + long IndexPosition, + int IndexCount, + int IndexSize) { int MaxIndex = -1; @@ -431,7 +427,7 @@ namespace Ryujinx.Graphics.Gpu { while (IndexCount -- > 0) { - ushort Value = Memory.ReadUInt16(IndexPosition); + ushort Value = (ushort)Vmm.ReadInt16(IndexPosition); IndexPosition += 2; @@ -445,7 +441,7 @@ namespace Ryujinx.Graphics.Gpu { while (IndexCount -- > 0) { - byte Value = Memory.ReadByte(IndexPosition++); + byte Value = Vmm.ReadByte(IndexPosition++); if (MaxIndex < Value) { @@ -457,7 +453,7 @@ namespace Ryujinx.Graphics.Gpu { while (IndexCount -- > 0) { - uint Value = Memory.ReadUInt32(IndexPosition); + uint Value = (uint)Vmm.ReadInt32(IndexPosition); IndexPosition += 2; @@ -475,75 +471,56 @@ namespace Ryujinx.Graphics.Gpu return MaxIndex + 1; } - private void QueryControl(AMemory Memory, NsGpuPBEntry PBEntry) + private void QueryControl(NvGpuVmm Vmm, NvGpuPBEntry PBEntry) { - if (TryGetCpuAddr(NvGpuEngine3dReg.QueryAddress, out long Position)) + long Position = MakeInt64From2xInt32(NvGpuEngine3dReg.QueryAddress); + + int Seq = Registers[(int)NvGpuEngine3dReg.QuerySequence]; + int Ctrl = Registers[(int)NvGpuEngine3dReg.QueryControl]; + + int Mode = Ctrl & 3; + + if (Mode == 0) { - int Seq = Registers[(int)NvGpuEngine3dReg.QuerySequence]; - int Ctrl = Registers[(int)NvGpuEngine3dReg.QueryControl]; - - int Mode = Ctrl & 3; - - if (Mode == 0) - { - //Write mode. - Memory.WriteInt32(Position, Seq); - } + //Write mode. + Vmm.WriteInt32(Position, Seq); } WriteRegister(PBEntry); } - private void CbData(AMemory Memory, NsGpuPBEntry PBEntry) + private void CbData(NvGpuVmm Vmm, NvGpuPBEntry PBEntry) { - if (TryGetCpuAddr(NvGpuEngine3dReg.ConstBufferNAddress, out long Position)) + long Position = MakeInt64From2xInt32(NvGpuEngine3dReg.ConstBufferAddress); + + int Offset = ReadRegister(NvGpuEngine3dReg.ConstBufferOffset); + + foreach (int Arg in PBEntry.Arguments) { - int Offset = ReadRegister(NvGpuEngine3dReg.ConstBufferNOffset); + Vmm.WriteInt32(Position + Offset, Arg); - foreach (int Arg in PBEntry.Arguments) - { - Memory.WriteInt32(Position + Offset, Arg); - - Offset += 4; - } - - WriteRegister(NvGpuEngine3dReg.ConstBufferNOffset, Offset); + Offset += 4; } + + WriteRegister(NvGpuEngine3dReg.ConstBufferOffset, Offset); } - private void CbBind(AMemory Memory, NsGpuPBEntry PBEntry) + private void CbBind(NvGpuVmm Vmm, NvGpuPBEntry PBEntry) { + int Stage = (PBEntry.Method - 0x904) >> 3; + int Index = PBEntry.Arguments[0]; bool Enabled = (Index & 1) != 0; Index = (Index >> 4) & 0x1f; - if (TryGetCpuAddr(NvGpuEngine3dReg.ConstBufferNAddress, out long Position)) - { - ConstBuffers[Index].Position = Position; - ConstBuffers[Index].Enabled = Enabled; + long Position = MakeInt64From2xInt32(NvGpuEngine3dReg.ConstBufferAddress); - ConstBuffers[Index].Size = ReadRegister(NvGpuEngine3dReg.ConstBufferNSize); - } - } + ConstBuffers[Stage][Index].Position = Position; + ConstBuffers[Stage][Index].Enabled = Enabled; - private int ReadCb(AMemory Memory, int Cbuf, int Offset) - { - long Position = ConstBuffers[Cbuf].Position; - - int Value = Memory.ReadInt32(Position + Offset); - - return Value; - } - - private bool TryGetCpuAddr(NvGpuEngine3dReg Reg, out long Position) - { - Position = MakeInt64From2xInt32(Reg); - - Position = Gpu.GetCpuAddr(Position); - - return Position != -1; + ConstBuffers[Stage][Index].Size = ReadRegister(NvGpuEngine3dReg.ConstBufferSize); } private long MakeInt64From2xInt32(NvGpuEngine3dReg Reg) @@ -553,7 +530,7 @@ namespace Ryujinx.Graphics.Gpu (uint)Registers[(int)Reg + 1]; } - private void WriteRegister(NsGpuPBEntry PBEntry) + private void WriteRegister(NvGpuPBEntry PBEntry) { int ArgsCount = PBEntry.Arguments.Count; diff --git a/Ryujinx.Graphics/Gpu/NvGpuEngine3dReg.cs b/Ryujinx.Core/Gpu/NvGpuEngine3dReg.cs similarity index 93% rename from Ryujinx.Graphics/Gpu/NvGpuEngine3dReg.cs rename to Ryujinx.Core/Gpu/NvGpuEngine3dReg.cs index 0d995619d7..823885ffd3 100644 --- a/Ryujinx.Graphics/Gpu/NvGpuEngine3dReg.cs +++ b/Ryujinx.Core/Gpu/NvGpuEngine3dReg.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.Graphics.Gpu +namespace Ryujinx.Core.Gpu { enum NvGpuEngine3dReg { @@ -53,9 +53,9 @@ namespace Ryujinx.Graphics.Gpu ShaderNOffset = 0x801, ShaderNMaxGprs = 0x803, ShaderNType = 0x804, - ConstBufferNSize = 0x8e0, - ConstBufferNAddress = 0x8e1, - ConstBufferNOffset = 0x8e3, + ConstBufferSize = 0x8e0, + ConstBufferAddress = 0x8e1, + ConstBufferOffset = 0x8e3, TextureCbIndex = 0x982 } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gpu/NvGpuFifo.cs b/Ryujinx.Core/Gpu/NvGpuFifo.cs similarity index 70% rename from Ryujinx.Graphics/Gpu/NvGpuFifo.cs rename to Ryujinx.Core/Gpu/NvGpuFifo.cs index 68c2902a53..d0e6fc14a0 100644 --- a/Ryujinx.Graphics/Gpu/NvGpuFifo.cs +++ b/Ryujinx.Core/Gpu/NvGpuFifo.cs @@ -1,16 +1,15 @@ -using ChocolArm64.Memory; using System.Collections.Concurrent; -namespace Ryujinx.Graphics.Gpu +namespace Ryujinx.Core.Gpu { public class NvGpuFifo { private const int MacrosCount = 0x80; private const int MacroIndexMask = MacrosCount - 1; - private NsGpu Gpu; + private NvGpu Gpu; - private ConcurrentQueue<(AMemory, NsGpuPBEntry)> BufferQueue; + private ConcurrentQueue<(NvGpuVmm, NvGpuPBEntry)> BufferQueue; private NvGpuEngine[] SubChannels; @@ -32,9 +31,9 @@ namespace Ryujinx.Graphics.Gpu Interpreter?.Fifo.Enqueue(Param); } - public void Execute(AMemory Memory, int Param) + public void Execute(NvGpuVmm Vmm, int Param) { - Interpreter?.Execute(Memory, Position, Param); + Interpreter?.Execute(Vmm, Position, Param); } } @@ -43,22 +42,22 @@ namespace Ryujinx.Graphics.Gpu private CachedMacro[] Macros; - public NvGpuFifo(NsGpu Gpu) + public NvGpuFifo(NvGpu Gpu) { this.Gpu = Gpu; - BufferQueue = new ConcurrentQueue<(AMemory, NsGpuPBEntry)>(); + BufferQueue = new ConcurrentQueue<(NvGpuVmm, NvGpuPBEntry)>(); SubChannels = new NvGpuEngine[8]; Macros = new CachedMacro[MacrosCount]; } - public void PushBuffer(AMemory Memory, NsGpuPBEntry[] Buffer) + public void PushBuffer(NvGpuVmm Vmm, NvGpuPBEntry[] Buffer) { - foreach (NsGpuPBEntry PBEntry in Buffer) + foreach (NvGpuPBEntry PBEntry in Buffer) { - BufferQueue.Enqueue((Memory, PBEntry)); + BufferQueue.Enqueue((Vmm, PBEntry)); } } @@ -69,9 +68,9 @@ namespace Ryujinx.Graphics.Gpu public bool Step() { - if (BufferQueue.TryDequeue(out (AMemory Memory, NsGpuPBEntry PBEntry) Tuple)) + if (BufferQueue.TryDequeue(out (NvGpuVmm Vmm, NvGpuPBEntry PBEntry) Tuple)) { - CallMethod(Tuple.Memory, Tuple.PBEntry); + CallMethod(Tuple.Vmm, Tuple.PBEntry); return true; } @@ -79,7 +78,7 @@ namespace Ryujinx.Graphics.Gpu return false; } - private void CallMethod(AMemory Memory, NsGpuPBEntry PBEntry) + private void CallMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry) { if (PBEntry.Method < 0x80) { @@ -103,11 +102,11 @@ namespace Ryujinx.Graphics.Gpu case NvGpuFifoMeth.SendMacroCodeData: { - long Position = Gpu.GetCpuAddr(CurrMacroPosition); + long Position = CurrMacroPosition; foreach (int Arg in PBEntry.Arguments) { - Memory.WriteInt32(Position, Arg); + Vmm.WriteInt32(Position, Arg); CurrMacroPosition += 4; @@ -127,8 +126,6 @@ namespace Ryujinx.Graphics.Gpu { long Position = (long)((ulong)PBEntry.Arguments[0] << 2); - Position = Gpu.GetCpuAddr(Position); - Macros[CurrMacroBindIndex] = new CachedMacro(this, Gpu.Engine3d, Position); break; @@ -139,22 +136,22 @@ namespace Ryujinx.Graphics.Gpu { switch (SubChannels[PBEntry.SubChannel]) { - case NvGpuEngine._2d: Call2dMethod(Memory, PBEntry); break; - case NvGpuEngine._3d: Call3dMethod(Memory, PBEntry); break; + case NvGpuEngine._2d: Call2dMethod(Vmm, PBEntry); break; + case NvGpuEngine._3d: Call3dMethod(Vmm, PBEntry); break; } } } - private void Call2dMethod(AMemory Memory, NsGpuPBEntry PBEntry) + private void Call2dMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry) { - Gpu.Engine2d.CallMethod(Memory, PBEntry); + Gpu.Engine2d.CallMethod(Vmm, PBEntry); } - private void Call3dMethod(AMemory Memory, NsGpuPBEntry PBEntry) + private void Call3dMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry) { if (PBEntry.Method < 0xe00) { - Gpu.Engine3d.CallMethod(Memory, PBEntry); + Gpu.Engine3d.CallMethod(Vmm, PBEntry); } else { @@ -169,7 +166,7 @@ namespace Ryujinx.Graphics.Gpu } else { - Macros[MacroIndex].Execute(Memory, PBEntry.Arguments[0]); + Macros[MacroIndex].Execute(Vmm, PBEntry.Arguments[0]); } } } diff --git a/Ryujinx.Graphics/Gpu/NvGpuFifoMeth.cs b/Ryujinx.Core/Gpu/NvGpuFifoMeth.cs similarity index 87% rename from Ryujinx.Graphics/Gpu/NvGpuFifoMeth.cs rename to Ryujinx.Core/Gpu/NvGpuFifoMeth.cs index 4287e25009..78ec908020 100644 --- a/Ryujinx.Graphics/Gpu/NvGpuFifoMeth.cs +++ b/Ryujinx.Core/Gpu/NvGpuFifoMeth.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.Graphics.Gpu +namespace Ryujinx.Core.Gpu { enum NvGpuFifoMeth { diff --git a/Ryujinx.Core/Gpu/NvGpuMethod.cs b/Ryujinx.Core/Gpu/NvGpuMethod.cs new file mode 100644 index 0000000000..42e1b5537f --- /dev/null +++ b/Ryujinx.Core/Gpu/NvGpuMethod.cs @@ -0,0 +1,4 @@ +namespace Ryujinx.Core.Gpu +{ + delegate void NvGpuMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry); +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gpu/NsGpuPBEntry.cs b/Ryujinx.Core/Gpu/NvGpuPBEntry.cs similarity index 78% rename from Ryujinx.Graphics/Gpu/NsGpuPBEntry.cs rename to Ryujinx.Core/Gpu/NvGpuPBEntry.cs index d405a93c6a..ebf35b9e42 100644 --- a/Ryujinx.Graphics/Gpu/NsGpuPBEntry.cs +++ b/Ryujinx.Core/Gpu/NvGpuPBEntry.cs @@ -1,9 +1,9 @@ using System; using System.Collections.ObjectModel; -namespace Ryujinx.Graphics.Gpu +namespace Ryujinx.Core.Gpu { - public struct NsGpuPBEntry + public struct NvGpuPBEntry { public int Method { get; private set; } @@ -13,7 +13,7 @@ namespace Ryujinx.Graphics.Gpu public ReadOnlyCollection Arguments => Array.AsReadOnly(m_Arguments); - public NsGpuPBEntry(int Method, int SubChannel, params int[] Arguments) + public NvGpuPBEntry(int Method, int SubChannel, params int[] Arguments) { this.Method = Method; this.SubChannel = SubChannel; diff --git a/Ryujinx.Graphics/Gpu/NvGpuPushBuffer.cs b/Ryujinx.Core/Gpu/NvGpuPushBuffer.cs similarity index 85% rename from Ryujinx.Graphics/Gpu/NvGpuPushBuffer.cs rename to Ryujinx.Core/Gpu/NvGpuPushBuffer.cs index 8cbb3288eb..d55886559e 100644 --- a/Ryujinx.Graphics/Gpu/NvGpuPushBuffer.cs +++ b/Ryujinx.Core/Gpu/NvGpuPushBuffer.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.IO; -namespace Ryujinx.Graphics.Gpu +namespace Ryujinx.Core.Gpu { public static class NvGpuPushBuffer { @@ -13,13 +13,13 @@ namespace Ryujinx.Graphics.Gpu IncrementOnce = 5 } - public static NsGpuPBEntry[] Decode(byte[] Data) + public static NvGpuPBEntry[] Decode(byte[] Data) { using (MemoryStream MS = new MemoryStream(Data)) { BinaryReader Reader = new BinaryReader(MS); - List PushBuffer = new List(); + List PushBuffer = new List(); bool CanRead() => MS.Position + 4 <= MS.Length; @@ -38,7 +38,7 @@ namespace Ryujinx.Graphics.Gpu { for (int Index = 0; Index < Args && CanRead(); Index++, Meth++) { - PushBuffer.Add(new NsGpuPBEntry(Meth, SubC, Reader.ReadInt32())); + PushBuffer.Add(new NvGpuPBEntry(Meth, SubC, Reader.ReadInt32())); } break; @@ -58,14 +58,14 @@ namespace Ryujinx.Graphics.Gpu Arguments[Index] = Reader.ReadInt32(); } - PushBuffer.Add(new NsGpuPBEntry(Meth, SubC, Arguments)); + PushBuffer.Add(new NvGpuPBEntry(Meth, SubC, Arguments)); break; } case SubmissionMode.Immediate: { - PushBuffer.Add(new NsGpuPBEntry(Meth, SubC, Args)); + PushBuffer.Add(new NvGpuPBEntry(Meth, SubC, Args)); break; } @@ -74,9 +74,9 @@ namespace Ryujinx.Graphics.Gpu { if (CanRead()) { - PushBuffer.Add(new NsGpuPBEntry(Meth, SubC, Reader.ReadInt32())); + PushBuffer.Add(new NvGpuPBEntry(Meth, SubC, Reader.ReadInt32())); } - + if (CanRead() && Args > 1) { int[] Arguments = new int[Args - 1]; @@ -86,7 +86,7 @@ namespace Ryujinx.Graphics.Gpu Arguments[Index] = Reader.ReadInt32(); } - PushBuffer.Add(new NsGpuPBEntry(Meth + 1, SubC, Arguments)); + PushBuffer.Add(new NvGpuPBEntry(Meth + 1, SubC, Arguments)); } break; diff --git a/Ryujinx.Core/Gpu/NvGpuVmm.cs b/Ryujinx.Core/Gpu/NvGpuVmm.cs new file mode 100644 index 0000000000..ad16aed625 --- /dev/null +++ b/Ryujinx.Core/Gpu/NvGpuVmm.cs @@ -0,0 +1,367 @@ +using ChocolArm64.Memory; + +namespace Ryujinx.Core.Gpu +{ + public class NvGpuVmm : IAMemory + { + public const long AddrSize = 1L << 40; + + private const int PTLvl0Bits = 14; + private const int PTLvl1Bits = 14; + private const int PTPageBits = 12; + + private const int PTLvl0Size = 1 << PTLvl0Bits; + private const int PTLvl1Size = 1 << PTLvl1Bits; + public const int PageSize = 1 << PTPageBits; + + private const int PTLvl0Mask = PTLvl0Size - 1; + private const int PTLvl1Mask = PTLvl1Size - 1; + public const int PageMask = PageSize - 1; + + private const int PTLvl0Bit = PTPageBits + PTLvl1Bits; + private const int PTLvl1Bit = PTPageBits; + + private const long PteUnmapped = -1; + private const long PteReserved = -2; + + private long[][] PageTable; + + private AMemory Memory; + + public NvGpuVmm(AMemory Memory) + { + this.Memory = Memory; + + PageTable = new long[PTLvl0Size][]; + } + + public long Map(long PA, long VA, long Size) + { + lock (PageTable) + { + for (long Offset = 0; Offset < Size; Offset += PageSize) + { + if (GetPte(VA + Offset) != PteReserved) + { + return Map(PA, Size); + } + } + + for (long Offset = 0; Offset < Size; Offset += PageSize) + { + SetPte(VA + Offset, PA + Offset); + } + } + + return VA; + } + + public long Map(long PA, long Size) + { + lock (PageTable) + { + long Position = GetFreePosition(Size); + + if (Position != -1) + { + for (long Offset = 0; Offset < Size; Offset += PageSize) + { + SetPte(Position + Offset, PA + Offset); + } + } + + return Position; + } + } + + public long Reserve(long VA, long Size, long Align) + { + lock (PageTable) + { + for (long Offset = 0; Offset < Size; Offset += PageSize) + { + if (IsPageInUse(VA + Offset)) + { + return Reserve(Size, Align); + } + } + + for (long Offset = 0; Offset < Size; Offset += PageSize) + { + SetPte(VA + Offset, PteReserved); + } + } + + return VA; + } + + public long Reserve(long Size, long Align) + { + lock (PageTable) + { + long Position = GetFreePosition(Size, Align); + + if (Position != -1) + { + for (long Offset = 0; Offset < Size; Offset += PageSize) + { + SetPte(Position + Offset, PteReserved); + } + } + + return Position; + } + } + + public void Free(long VA, long Size) + { + lock (PageTable) + { + for (long Offset = 0; Offset < Size; Offset += PageSize) + { + SetPte(VA + Offset, PteUnmapped); + } + } + } + + private long GetFreePosition(long Size, long Align = 1) + { + long Position = 0; + long FreeSize = 0; + + if (Align < 1) + { + Align = 1; + } + + Align = (Align + PageMask) & ~PageMask; + + while (Position + FreeSize < AddrSize) + { + if (!IsPageInUse(Position + FreeSize)) + { + FreeSize += PageSize; + + if (FreeSize >= Size) + { + return Position; + } + } + else + { + Position += FreeSize + PageSize; + FreeSize = 0; + + long Remainder = Position % Align; + + if (Remainder != 0) + { + Position = (Position - Remainder) + Align; + } + } + } + + return -1; + } + + public long GetCpuAddr(long VA) + { + long BasePos = GetPte(VA); + + if (BasePos < 0) + { + return -1; + } + + return BasePos + (VA & PageMask); + } + + public bool IsRegionFree(long VA, long Size) + { + for (long Offset = 0; Offset < Size; Offset += PageSize) + { + if (IsPageInUse(VA + Offset)) + { + return false; + } + } + + return true; + } + + private bool IsPageInUse(long VA) + { + if (VA >> PTLvl0Bits + PTLvl1Bits + PTPageBits != 0) + { + return false; + } + + long L0 = (VA >> PTLvl0Bit) & PTLvl0Mask; + long L1 = (VA >> PTLvl1Bit) & PTLvl1Mask; + + if (PageTable[L0] == null) + { + return false; + } + + return PageTable[L0][L1] != PteUnmapped; + } + + private long GetPte(long Position) + { + long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask; + long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask; + + if (PageTable[L0] == null) + { + return -1; + } + + return PageTable[L0][L1]; + } + + private void SetPte(long Position, long TgtAddr) + { + long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask; + long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask; + + if (PageTable[L0] == null) + { + PageTable[L0] = new long[PTLvl1Size]; + + for (int Index = 0; Index < PTLvl1Size; Index++) + { + PageTable[L0][Index] = PteUnmapped; + } + } + + PageTable[L0][L1] = TgtAddr; + } + + public byte ReadByte(long Position) + { + Position = GetCpuAddr(Position); + + return Memory.ReadByte(Position); + } + + public ushort ReadUInt16(long Position) + { + Position = GetCpuAddr(Position); + + return Memory.ReadUInt16(Position); + } + + public uint ReadUInt32(long Position) + { + Position = GetCpuAddr(Position); + + return Memory.ReadUInt32(Position); + } + + public ulong ReadUInt64(long Position) + { + Position = GetCpuAddr(Position); + + return Memory.ReadUInt64(Position); + } + + public sbyte ReadSByte(long Position) + { + Position = GetCpuAddr(Position); + + return Memory.ReadSByte(Position); + } + + public short ReadInt16(long Position) + { + Position = GetCpuAddr(Position); + + return Memory.ReadInt16(Position); + } + + public int ReadInt32(long Position) + { + Position = GetCpuAddr(Position); + + return Memory.ReadInt32(Position); + } + + public long ReadInt64(long Position) + { + Position = GetCpuAddr(Position); + + return Memory.ReadInt64(Position); + } + + public byte[] ReadBytes(long Position, long Size) + { + Position = GetCpuAddr(Position); + + return AMemoryHelper.ReadBytes(Memory, Position, Size); + } + + public void WriteByte(long Position, byte Value) + { + Position = GetCpuAddr(Position); + + Memory.WriteByte(Position, Value); + } + + public void WriteUInt16(long Position, ushort Value) + { + Position = GetCpuAddr(Position); + + Memory.WriteUInt16(Position, Value); + } + + public void WriteUInt32(long Position, uint Value) + { + Position = GetCpuAddr(Position); + + Memory.WriteUInt32(Position, Value); + } + + public void WriteUInt64(long Position, ulong Value) + { + Position = GetCpuAddr(Position); + + Memory.WriteUInt64(Position, Value); + } + + public void WriteSByte(long Position, sbyte Value) + { + Position = GetCpuAddr(Position); + + Memory.WriteSByte(Position, Value); + } + + public void WriteInt16(long Position, short Value) + { + Position = GetCpuAddr(Position); + + Memory.WriteInt16(Position, Value); + } + + public void WriteInt32(long Position, int Value) + { + Position = GetCpuAddr(Position); + + Memory.WriteInt32(Position, Value); + } + + public void WriteInt64(long Position, long Value) + { + Position = GetCpuAddr(Position); + + Memory.WriteInt64(Position, Value); + } + + public void WriteBytes(long Position, byte[] Data) + { + Position = GetCpuAddr(Position); + + AMemoryHelper.WriteBytes(Memory, Position, Data); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gpu/Texture.cs b/Ryujinx.Core/Gpu/Texture.cs similarity index 97% rename from Ryujinx.Graphics/Gpu/Texture.cs rename to Ryujinx.Core/Gpu/Texture.cs index cbfa683dc9..39a35059bc 100644 --- a/Ryujinx.Graphics/Gpu/Texture.cs +++ b/Ryujinx.Core/Gpu/Texture.cs @@ -1,6 +1,6 @@ using Ryujinx.Graphics.Gal; -namespace Ryujinx.Graphics.Gpu +namespace Ryujinx.Core.Gpu { public struct Texture { diff --git a/Ryujinx.Graphics/Gpu/TextureFactory.cs b/Ryujinx.Core/Gpu/TextureFactory.cs similarity index 77% rename from Ryujinx.Graphics/Gpu/TextureFactory.cs rename to Ryujinx.Core/Gpu/TextureFactory.cs index 7f8580d987..68b48a1fbc 100644 --- a/Ryujinx.Graphics/Gpu/TextureFactory.cs +++ b/Ryujinx.Core/Gpu/TextureFactory.cs @@ -1,14 +1,13 @@ -using ChocolArm64.Memory; using Ryujinx.Graphics.Gal; using System; -namespace Ryujinx.Graphics.Gpu +namespace Ryujinx.Core.Gpu { static class TextureFactory { - public static GalTexture MakeTexture(NsGpu Gpu, AMemory Memory, long TicPosition) + public static GalTexture MakeTexture(NvGpu Gpu, NvGpuVmm Vmm, long TicPosition) { - int[] Tic = ReadWords(Memory, TicPosition, 8); + int[] Tic = ReadWords(Vmm, TicPosition, 8); GalTextureFormat Format = (GalTextureFormat)(Tic[0] & 0x7f); @@ -16,8 +15,6 @@ namespace Ryujinx.Graphics.Gpu TextureAddress |= (long)((ushort)Tic[2]) << 32; - TextureAddress = Gpu.GetCpuAddr(TextureAddress); - TextureSwizzle Swizzle = (TextureSwizzle)((Tic[2] >> 21) & 7); int Pitch = (Tic[3] & 0xffff) << 5; @@ -38,14 +35,14 @@ namespace Ryujinx.Graphics.Gpu Swizzle, Format); - byte[] Data = TextureReader.Read(Memory, Texture); + byte[] Data = TextureReader.Read(Vmm, Texture); return new GalTexture(Data, Width, Height, Format); } - public static GalTextureSampler MakeSampler(NsGpu Gpu, AMemory Memory, long TscPosition) + public static GalTextureSampler MakeSampler(NvGpu Gpu, NvGpuVmm Vmm, long TscPosition) { - int[] Tsc = ReadWords(Memory, TscPosition, 8); + int[] Tsc = ReadWords(Vmm, TscPosition, 8); GalTextureWrap AddressU = (GalTextureWrap)((Tsc[0] >> 0) & 7); GalTextureWrap AddressV = (GalTextureWrap)((Tsc[0] >> 3) & 7); @@ -71,13 +68,13 @@ namespace Ryujinx.Graphics.Gpu BorderColor); } - private static int[] ReadWords(AMemory Memory, long Position, int Count) + private static int[] ReadWords(NvGpuVmm Vmm, long Position, int Count) { int[] Words = new int[Count]; for (int Index = 0; Index < Count; Index++, Position += 4) { - Words[Index] = Memory.ReadInt32(Position); + Words[Index] = Vmm.ReadInt32(Position); } return Words; diff --git a/Ryujinx.Graphics/Gpu/TextureHelper.cs b/Ryujinx.Core/Gpu/TextureHelper.cs similarity index 95% rename from Ryujinx.Graphics/Gpu/TextureHelper.cs rename to Ryujinx.Core/Gpu/TextureHelper.cs index d3c2ac14b5..1a5ffca4a2 100644 --- a/Ryujinx.Graphics/Gpu/TextureHelper.cs +++ b/Ryujinx.Core/Gpu/TextureHelper.cs @@ -1,6 +1,6 @@ using System; -namespace Ryujinx.Graphics.Gpu +namespace Ryujinx.Core.Gpu { static class TextureHelper { diff --git a/Ryujinx.Graphics/Gpu/TextureReader.cs b/Ryujinx.Core/Gpu/TextureReader.cs similarity index 81% rename from Ryujinx.Graphics/Gpu/TextureReader.cs rename to Ryujinx.Core/Gpu/TextureReader.cs index 17fd95c5c5..a36931499f 100644 --- a/Ryujinx.Graphics/Gpu/TextureReader.cs +++ b/Ryujinx.Core/Gpu/TextureReader.cs @@ -2,11 +2,11 @@ using ChocolArm64.Memory; using Ryujinx.Graphics.Gal; using System; -namespace Ryujinx.Graphics.Gpu +namespace Ryujinx.Core.Gpu { public static class TextureReader { - public static byte[] Read(AMemory Memory, Texture Texture) + public static byte[] Read(IAMemory Memory, Texture Texture) { switch (Texture.Format) { @@ -23,7 +23,7 @@ namespace Ryujinx.Graphics.Gpu throw new NotImplementedException(Texture.Format.ToString()); } - private unsafe static byte[] Read2Bpp(AMemory Memory, Texture Texture) + private unsafe static byte[] Read2Bpp(IAMemory Memory, Texture Texture) { int Width = Texture.Width; int Height = Texture.Height; @@ -41,7 +41,7 @@ namespace Ryujinx.Graphics.Gpu { long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y); - short Pixel = Memory.ReadInt16Unchecked(Texture.Position + Offset); + short Pixel = Memory.ReadInt16(Texture.Position + Offset); *(short*)(BuffPtr + OutOffs) = Pixel; @@ -52,7 +52,7 @@ namespace Ryujinx.Graphics.Gpu return Output; } - private unsafe static byte[] Read4Bpp(AMemory Memory, Texture Texture) + private unsafe static byte[] Read4Bpp(IAMemory Memory, Texture Texture) { int Width = Texture.Width; int Height = Texture.Height; @@ -70,7 +70,7 @@ namespace Ryujinx.Graphics.Gpu { long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y); - int Pixel = Memory.ReadInt32Unchecked(Texture.Position + Offset); + int Pixel = Memory.ReadInt32(Texture.Position + Offset); *(int*)(BuffPtr + OutOffs) = Pixel; @@ -81,7 +81,7 @@ namespace Ryujinx.Graphics.Gpu return Output; } - private unsafe static byte[] Read8Bpt4x4(AMemory Memory, Texture Texture) + private unsafe static byte[] Read8Bpt4x4(IAMemory Memory, Texture Texture) { int Width = (Texture.Width + 3) / 4; int Height = (Texture.Height + 3) / 4; @@ -99,7 +99,7 @@ namespace Ryujinx.Graphics.Gpu { long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y); - long Tile = Memory.ReadInt64Unchecked(Texture.Position + Offset); + long Tile = Memory.ReadInt64(Texture.Position + Offset); *(long*)(BuffPtr + OutOffs) = Tile; @@ -110,7 +110,7 @@ namespace Ryujinx.Graphics.Gpu return Output; } - private unsafe static byte[] Read16Bpt4x4(AMemory Memory, Texture Texture) + private unsafe static byte[] Read16Bpt4x4(IAMemory Memory, Texture Texture) { int Width = (Texture.Width + 3) / 4; int Height = (Texture.Height + 3) / 4; @@ -128,8 +128,8 @@ namespace Ryujinx.Graphics.Gpu { long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y); - long Tile0 = Memory.ReadInt64Unchecked(Texture.Position + Offset + 0); - long Tile1 = Memory.ReadInt64Unchecked(Texture.Position + Offset + 8); + long Tile0 = Memory.ReadInt64(Texture.Position + Offset + 0); + long Tile1 = Memory.ReadInt64(Texture.Position + Offset + 8); *(long*)(BuffPtr + OutOffs + 0) = Tile0; *(long*)(BuffPtr + OutOffs + 8) = Tile1; diff --git a/Ryujinx.Graphics/Gpu/TextureSwizzle.cs b/Ryujinx.Core/Gpu/TextureSwizzle.cs similarity index 87% rename from Ryujinx.Graphics/Gpu/TextureSwizzle.cs rename to Ryujinx.Core/Gpu/TextureSwizzle.cs index 7d99279cd4..3214f45f81 100644 --- a/Ryujinx.Graphics/Gpu/TextureSwizzle.cs +++ b/Ryujinx.Core/Gpu/TextureSwizzle.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.Graphics.Gpu +namespace Ryujinx.Core.Gpu { public enum TextureSwizzle { diff --git a/Ryujinx.Graphics/Gpu/TextureWriter.cs b/Ryujinx.Core/Gpu/TextureWriter.cs similarity index 77% rename from Ryujinx.Graphics/Gpu/TextureWriter.cs rename to Ryujinx.Core/Gpu/TextureWriter.cs index 2f25de73fc..957aef3d3b 100644 --- a/Ryujinx.Graphics/Gpu/TextureWriter.cs +++ b/Ryujinx.Core/Gpu/TextureWriter.cs @@ -2,11 +2,11 @@ using ChocolArm64.Memory; using Ryujinx.Graphics.Gal; using System; -namespace Ryujinx.Graphics.Gpu +namespace Ryujinx.Core.Gpu { public static class TextureWriter { - public static void Write(AMemory Memory, Texture Texture, byte[] Data) + public static void Write(IAMemory Memory, Texture Texture, byte[] Data) { switch (Texture.Format) { @@ -17,7 +17,7 @@ namespace Ryujinx.Graphics.Gpu } } - private unsafe static void Write4Bpp(AMemory Memory, Texture Texture, byte[] Data) + private unsafe static void Write4Bpp(IAMemory Memory, Texture Texture, byte[] Data) { int Width = Texture.Width; int Height = Texture.Height; @@ -35,7 +35,7 @@ namespace Ryujinx.Graphics.Gpu int Pixel = *(int*)(BuffPtr + InOffs); - Memory.WriteInt32Unchecked(Texture.Position + Offset, Pixel); + Memory.WriteInt32(Texture.Position + Offset, Pixel); InOffs += 4; } diff --git a/Ryujinx.Core/OsHle/Horizon.cs b/Ryujinx.Core/OsHle/Horizon.cs index 0cc3d815ad..1d4098c7d4 100644 --- a/Ryujinx.Core/OsHle/Horizon.cs +++ b/Ryujinx.Core/OsHle/Horizon.cs @@ -20,6 +20,8 @@ namespace Ryujinx.Core.OsHle public SystemStateMgr SystemState { get; private set; } + internal MemoryAllocator Allocator { get; private set; } + internal HSharedMem HidSharedMem { get; private set; } internal HSharedMem FontSharedMem { get; private set; } @@ -35,6 +37,8 @@ namespace Ryujinx.Core.OsHle SystemState = new SystemStateMgr(); + Allocator = new MemoryAllocator(); + HidSharedMem = new HSharedMem(); FontSharedMem = new HSharedMem(); diff --git a/Ryujinx.Core/OsHle/MemoryAllocator.cs b/Ryujinx.Core/OsHle/MemoryAllocator.cs new file mode 100644 index 0000000000..e57f52640d --- /dev/null +++ b/Ryujinx.Core/OsHle/MemoryAllocator.cs @@ -0,0 +1,12 @@ +using System; + +namespace Ryujinx.Core.OsHle +{ + class MemoryAllocator + { + public bool TryAllocate(long Size, out long Address) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Process.cs b/Ryujinx.Core/OsHle/Process.cs index b8c088563f..ac4d72b68b 100644 --- a/Ryujinx.Core/OsHle/Process.cs +++ b/Ryujinx.Core/OsHle/Process.cs @@ -412,10 +412,6 @@ namespace Ryujinx.Core.OsHle INvDrvServices.Fds.DeleteProcess(this); - INvDrvServices.NvMaps .DeleteProcess(this); - INvDrvServices.NvMapsById.DeleteProcess(this); - INvDrvServices.NvMapsFb .DeleteProcess(this); - AppletState.Dispose(); SvcHandler.Dispose(); diff --git a/Ryujinx.Core/OsHle/Services/Nv/INvDrvServices.cs b/Ryujinx.Core/OsHle/Services/Nv/INvDrvServices.cs index 2652724d5b..e32815351f 100644 --- a/Ryujinx.Core/OsHle/Services/Nv/INvDrvServices.cs +++ b/Ryujinx.Core/OsHle/Services/Nv/INvDrvServices.cs @@ -1,31 +1,36 @@ using ChocolArm64.Memory; -using Ryujinx.Core.Logging; using Ryujinx.Core.OsHle.Handles; using Ryujinx.Core.OsHle.Ipc; -using Ryujinx.Core.OsHle.Utilities; -using Ryujinx.Graphics.Gpu; +using Ryujinx.Core.OsHle.Services.Nv.NvGpuAS; +using Ryujinx.Core.OsHle.Services.Nv.NvHostChannel; +using Ryujinx.Core.OsHle.Services.Nv.NvHostCtrl; +using Ryujinx.Core.OsHle.Services.Nv.NvHostCtrlGpu; +using Ryujinx.Core.OsHle.Services.Nv.NvMap; using System; using System.Collections.Generic; -using System.IO; namespace Ryujinx.Core.OsHle.Services.Nv { class INvDrvServices : IpcService, IDisposable { - private delegate long ServiceProcessIoctl(ServiceCtx Context); + private delegate int ProcessIoctl(ServiceCtx Context, int Cmd); private Dictionary m_Commands; public override IReadOnlyDictionary Commands => m_Commands; - private Dictionary<(string, int), ServiceProcessIoctl> IoctlCmds; + private static Dictionary IoctlProcessors = + new Dictionary() + { + { "/dev/nvhost-as-gpu", NvGpuASIoctl .ProcessIoctl }, + { "/dev/nvhost-ctrl", NvHostCtrlIoctl .ProcessIoctl }, + { "/dev/nvhost-ctrl-gpu", NvHostCtrlGpuIoctl.ProcessIoctl }, + { "/dev/nvhost-gpu", NvHostChannelIoctl.ProcessIoctl }, + { "/dev/nvmap", NvMapIoctl .ProcessIoctl } + }; public static GlobalStateTable Fds { get; private set; } - public static GlobalStateTable NvMaps { get; private set; } - public static GlobalStateTable NvMapsById { get; private set; } - public static GlobalStateTable NvMapsFb { get; private set; } - private KEvent Event; public INvDrvServices() @@ -37,42 +42,7 @@ namespace Ryujinx.Core.OsHle.Services.Nv { 2, Close }, { 3, Initialize }, { 4, QueryEvent }, - { 8, SetClientPid }, - }; - - IoctlCmds = new Dictionary<(string, int), ServiceProcessIoctl>() - { - { ("/dev/nvhost-as-gpu", 0x4101), NvGpuAsIoctlBindChannel }, - { ("/dev/nvhost-as-gpu", 0x4102), NvGpuAsIoctlAllocSpace }, - { ("/dev/nvhost-as-gpu", 0x4105), NvGpuAsIoctlUnmap }, - { ("/dev/nvhost-as-gpu", 0x4106), NvGpuAsIoctlMapBufferEx }, - { ("/dev/nvhost-as-gpu", 0x4108), NvGpuAsIoctlGetVaRegions }, - { ("/dev/nvhost-as-gpu", 0x4109), NvGpuAsIoctlInitializeEx }, - { ("/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 }, - { ("/dev/nvhost-ctrl-gpu", 0x4705), NvGpuIoctlGetCharacteristics }, - { ("/dev/nvhost-ctrl-gpu", 0x4706), NvGpuIoctlGetTpcMasks }, - { ("/dev/nvhost-ctrl-gpu", 0x4714), NvGpuIoctlZbcGetActiveSlotMask }, - { ("/dev/nvhost-gpu", 0x4714), NvMapIoctlChannelSetUserData }, - { ("/dev/nvhost-gpu", 0x4801), NvMapIoctlChannelSetNvMap }, - { ("/dev/nvhost-gpu", 0x4808), NvMapIoctlChannelSubmitGpFifo }, - { ("/dev/nvhost-gpu", 0x4809), NvMapIoctlChannelAllocObjCtx }, - { ("/dev/nvhost-gpu", 0x480b), NvMapIoctlChannelZcullBind }, - { ("/dev/nvhost-gpu", 0x480c), NvMapIoctlChannelSetErrorNotifier }, - { ("/dev/nvhost-gpu", 0x480d), NvMapIoctlChannelSetPriority }, - { ("/dev/nvhost-gpu", 0x481a), NvMapIoctlChannelAllocGpFifoEx2 }, - { ("/dev/nvmap", 0x0101), NvMapIocCreate }, - { ("/dev/nvmap", 0x0103), NvMapIocFromId }, - { ("/dev/nvmap", 0x0104), NvMapIocAlloc }, - { ("/dev/nvmap", 0x0105), NvMapIocFree }, - { ("/dev/nvmap", 0x0109), NvMapIocParam }, - { ("/dev/nvmap", 0x010e), NvMapIocGetId }, + { 8, SetClientPid } }; Event = new KEvent(); @@ -81,10 +51,6 @@ namespace Ryujinx.Core.OsHle.Services.Nv static INvDrvServices() { Fds = new GlobalStateTable(); - - NvMaps = new GlobalStateTable(); - NvMapsById = new GlobalStateTable(); - NvMapsFb = new GlobalStateTable(); } public long Open(ServiceCtx Context) @@ -104,22 +70,24 @@ namespace Ryujinx.Core.OsHle.Services.Nv public long Ioctl(ServiceCtx Context) { int Fd = Context.RequestData.ReadInt32(); - int Cmd = Context.RequestData.ReadInt32() & 0xffff; + int Cmd = Context.RequestData.ReadInt32(); NvFd FdData = Fds.GetData(Context.Process, Fd); - long Position = Context.Request.GetSendBuffPtr(); + int Result; - Context.ResponseData.Write(0); - - if (IoctlCmds.TryGetValue((FdData.Name, Cmd), out ServiceProcessIoctl ProcReq)) + if (IoctlProcessors.TryGetValue(FdData.Name, out ProcessIoctl Process)) { - return ProcReq(Context); + Result = Process(Context, Cmd); } else { throw new NotImplementedException($"{FdData.Name} {Cmd:x4}"); } + + Context.ResponseData.Write(Result); + + return 0; } public long Close(ServiceCtx Context) @@ -138,9 +106,9 @@ namespace Ryujinx.Core.OsHle.Services.Nv long TransferMemSize = Context.RequestData.ReadInt64(); int TransferMemHandle = Context.Request.HandleDesc.ToCopy[0]; - Context.ResponseData.Write(0); + NvMapIoctl.InitializeNvMap(Context); - NvMapsFb.Add(Context.Process, 0, new NvMapFb()); + Context.ResponseData.Write(0); return 0; } @@ -169,661 +137,6 @@ namespace Ryujinx.Core.OsHle.Services.Nv return 0; } - private long NvGpuAsIoctlBindChannel(ServiceCtx Context) - { - long Position = Context.Request.GetSendBuffPtr(); - - int Fd = Context.Memory.ReadInt32(Position); - - return 0; - } - - private long NvGpuAsIoctlAllocSpace(ServiceCtx Context) - { - long Position = Context.Request.GetSendBuffPtr(); - - MemReader Reader = new MemReader(Context.Memory, Position); - - int Pages = Reader.ReadInt32(); - int PageSize = Reader.ReadInt32(); - int Flags = Reader.ReadInt32(); - int Padding = Reader.ReadInt32(); - long Align = Reader.ReadInt64(); - - if ((Flags & 1) != 0) - { - Align = Context.Ns.Gpu.ReserveMemory(Align, (long)Pages * PageSize, 1); - } - else - { - Align = Context.Ns.Gpu.ReserveMemory((long)Pages * PageSize, Align); - } - - Context.Memory.WriteInt64(Position + 0x10, Align); - - return 0; - } - - private long NvGpuAsIoctlUnmap(ServiceCtx Context) - { - long Position = Context.Request.GetSendBuffPtr(); - - MemReader Reader = new MemReader(Context.Memory, Position); - - long Offset = Reader.ReadInt64(); - - Context.Ns.Gpu.MemoryMgr.Unmap(Offset, 0x10000); - - return 0; - } - - private long NvGpuAsIoctlMapBufferEx(ServiceCtx Context) - { - long Position = Context.Request.GetSendBuffPtr(); - - MemReader Reader = new MemReader(Context.Memory, Position); - - int Flags = Reader.ReadInt32(); - int Kind = Reader.ReadInt32(); - int Handle = Reader.ReadInt32(); - int PageSize = Reader.ReadInt32(); - long BuffAddr = Reader.ReadInt64(); - long MapSize = Reader.ReadInt64(); - long Offset = Reader.ReadInt64(); - - if (Handle == 0) - { - //This is used to store offsets for the Framebuffer(s); - NvMapFb MapFb = (NvMapFb)NvMapsFb.GetData(Context.Process, 0); - - MapFb.AddBufferOffset(BuffAddr); - - return 0; - } - - NvMap Map = NvMaps.GetData(Context.Process, Handle); - - if (Map == null) - { - Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"invalid NvMap Handle {Handle}!"); - - return -1; //TODO: Corrent error code. - } - - if ((Flags & 1) != 0) - { - Offset = Context.Ns.Gpu.MapMemory(Map.CpuAddress, Offset, Map.Size); - } - else - { - Offset = Context.Ns.Gpu.MapMemory(Map.CpuAddress, Map.Size); - } - - Context.Memory.WriteInt64(Position + 0x20, Offset); - - Map.GpuAddress = Offset; - - return 0; - } - - private long NvGpuAsIoctlGetVaRegions(ServiceCtx Context) - { - long Position = Context.Request.GetSendBuffPtr(); - - MemReader Reader = new MemReader(Context.Memory, Position); - MemWriter Writer = new MemWriter(Context.Memory, Position); - - long Unused = Reader.ReadInt64(); - int BuffSize = Reader.ReadInt32(); - int Padding = Reader.ReadInt32(); - - BuffSize = 0x30; - - Writer.WriteInt64(Unused); - Writer.WriteInt32(BuffSize); - Writer.WriteInt32(Padding); - - Writer.WriteInt64(0); - Writer.WriteInt32(0); - Writer.WriteInt32(0); - Writer.WriteInt64(0); - - Writer.WriteInt64(0); - Writer.WriteInt32(0); - Writer.WriteInt32(0); - Writer.WriteInt64(0); - - return 0; - } - - private long NvGpuAsIoctlInitializeEx(ServiceCtx Context) - { - long Position = Context.Request.GetSendBuffPtr(); - - MemReader Reader = new MemReader(Context.Memory, Position); - - int BigPageSize = Reader.ReadInt32(); - int AsFd = Reader.ReadInt32(); - int Flags = Reader.ReadInt32(); - int Reserved = Reader.ReadInt32(); - long Unknown10 = Reader.ReadInt64(); - long Unknown18 = Reader.ReadInt64(); - long Unknown20 = Reader.ReadInt64(); - - return 0; - } - - private long NvGpuAsIoctlRemap(ServiceCtx Context) - { - Context.RequestData.BaseStream.Seek(-4, SeekOrigin.Current); - - int Cmd = Context.RequestData.ReadInt32(); - - int Size = (Cmd >> 16) & 0xff; - - int Count = Size / 0x18; - - long Position = Context.Request.GetSendBuffPtr(); - - MemReader Reader = new MemReader(Context.Memory, Position); - - for (int Index = 0; Index < Count; Index++) - { - int Flags = Reader.ReadInt32(); - int Kind = Reader.ReadInt32(); - int Handle = Reader.ReadInt32(); - int Padding = Reader.ReadInt32(); - int Offset = Reader.ReadInt32(); - int Pages = Reader.ReadInt32(); - - NvMap Map = NvMaps.GetData(Context.Process, Handle); - - if (Map == null) - { - Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"invalid NvMap Handle {Handle}!"); - - return -1; //TODO: Corrent error code. - } - - Context.Ns.Gpu.MapMemory(Map.CpuAddress, - (long)(uint)Offset << 16, - (long)(uint)Pages << 16); - } - - //TODO - - return 0; - } - - private long NvHostIoctlCtrlGetConfig(ServiceCtx Context) - { - long Position = Context.Request.GetSendBuffPtr(); - - MemReader Reader = new MemReader(Context.Memory, Position); - MemWriter Writer = new MemWriter(Context.Memory, Position + 0x82); - - for (int Index = 0; Index < 0x101; Index++) - { - Writer.WriteByte(0); - } - - return 0; - } - - private long NvHostIoctlCtrlEventWait(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 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(); - - Context.Memory.WriteInt32(Position, 1); - - return 0; - } - - private long NvGpuIoctlZcullGetInfo(ServiceCtx Context) - { - long Position = Context.Request.GetSendBuffPtr(); - - MemWriter Writer = new MemWriter(Context.Memory, Position); - - Writer.WriteInt32(0); - Writer.WriteInt32(0); - Writer.WriteInt32(0); - Writer.WriteInt32(0); - Writer.WriteInt32(0); - Writer.WriteInt32(0); - Writer.WriteInt32(0); - Writer.WriteInt32(0); - Writer.WriteInt32(0); - Writer.WriteInt32(0); - - return 0; - } - - private long NvGpuIoctlZbcSetTable(ServiceCtx Context) - { - long Position = Context.Request.GetSendBuffPtr(); - - MemReader Reader = new MemReader(Context.Memory, Position); - - int[] ColorDs = new int[4]; - int[] ColorL2 = new int[4]; - - ColorDs[0] = Reader.ReadInt32(); - ColorDs[1] = Reader.ReadInt32(); - ColorDs[2] = Reader.ReadInt32(); - ColorDs[3] = Reader.ReadInt32(); - - ColorL2[0] = Reader.ReadInt32(); - ColorL2[1] = Reader.ReadInt32(); - ColorL2[2] = Reader.ReadInt32(); - ColorL2[3] = Reader.ReadInt32(); - - int Depth = Reader.ReadInt32(); - int Format = Reader.ReadInt32(); - int Type = Reader.ReadInt32(); - - return 0; - } - - private long NvGpuIoctlGetCharacteristics(ServiceCtx Context) - { - long Position = Context.Request.GetSendBuffPtr(); - - MemReader Reader = new MemReader(Context.Memory, Position); - MemWriter Writer = new MemWriter(Context.Memory, Position); - - //Note: We should just ignore the BuffAddr, because official code - //does __memcpy_device from Position + 0x10 to BuffAddr. - long BuffSize = Reader.ReadInt64(); - long BuffAddr = Reader.ReadInt64(); - - BuffSize = 0xa0; - - Writer.WriteInt64(BuffSize); - Writer.WriteInt64(BuffAddr); - Writer.WriteInt32(0x120); //NVGPU_GPU_ARCH_GM200 - Writer.WriteInt32(0xb); //NVGPU_GPU_IMPL_GM20B - Writer.WriteInt32(0xa1); - Writer.WriteInt32(1); - Writer.WriteInt64(0x40000); - Writer.WriteInt64(0); - Writer.WriteInt32(2); - Writer.WriteInt32(0x20); //NVGPU_GPU_BUS_TYPE_AXI - Writer.WriteInt32(0x20000); - Writer.WriteInt32(0x20000); - Writer.WriteInt32(0x1b); - Writer.WriteInt32(0x30000); - Writer.WriteInt32(1); - Writer.WriteInt32(0x503); - Writer.WriteInt32(0x503); - Writer.WriteInt32(0x80); - Writer.WriteInt32(0x28); - Writer.WriteInt32(0); - Writer.WriteInt64(0x55); - Writer.WriteInt32(0x902d); //FERMI_TWOD_A - Writer.WriteInt32(0xb197); //MAXWELL_B - Writer.WriteInt32(0xb1c0); //MAXWELL_COMPUTE_B - Writer.WriteInt32(0xb06f); //MAXWELL_CHANNEL_GPFIFO_A - Writer.WriteInt32(0xa140); //KEPLER_INLINE_TO_MEMORY_B - Writer.WriteInt32(0xb0b5); //MAXWELL_DMA_COPY_A - Writer.WriteInt32(1); - Writer.WriteInt32(0); - Writer.WriteInt32(2); - Writer.WriteInt32(1); - Writer.WriteInt32(0); - Writer.WriteInt32(1); - Writer.WriteInt32(0x21d70); - Writer.WriteInt32(0); - Writer.WriteByte((byte)'g'); - Writer.WriteByte((byte)'m'); - Writer.WriteByte((byte)'2'); - Writer.WriteByte((byte)'0'); - Writer.WriteByte((byte)'b'); - Writer.WriteByte((byte)'\0'); - Writer.WriteByte((byte)'\0'); - Writer.WriteByte((byte)'\0'); - Writer.WriteInt64(0); - - return 0; - } - - private long NvGpuIoctlGetTpcMasks(ServiceCtx Context) - { - long Position = Context.Request.GetSendBuffPtr(); - - MemReader Reader = new MemReader(Context.Memory, Position); - - int MaskBuffSize = Reader.ReadInt32(); - int Reserved = Reader.ReadInt32(); - long MaskBuffAddr = Reader.ReadInt64(); - long Unknown = Reader.ReadInt64(); - - return 0; - } - - private long NvGpuIoctlZbcGetActiveSlotMask(ServiceCtx Context) - { - long Position = Context.Request.GetSendBuffPtr(); - - Context.Memory.WriteInt32(Position + 0, 7); - Context.Memory.WriteInt32(Position + 4, 1); - - return 0; - } - - private long NvMapIoctlChannelSetUserData(ServiceCtx Context) - { - long Position = Context.Request.GetSendBuffPtr(); - - return 0; - } - - private long NvMapIoctlChannelSetNvMap(ServiceCtx Context) - { - long Position = Context.Request.GetSendBuffPtr(); - - int Fd = Context.Memory.ReadInt32(Position); - - return 0; - } - - private long NvMapIoctlChannelSubmitGpFifo(ServiceCtx Context) - { - long Position = Context.Request.GetSendBuffPtr(); - - MemReader Reader = new MemReader(Context.Memory, Position); - MemWriter Writer = new MemWriter(Context.Memory, Position + 0x10); - - long GpFifo = Reader.ReadInt64(); - int Count = Reader.ReadInt32(); - int Flags = Reader.ReadInt32(); - int FenceId = Reader.ReadInt32(); - int FenceVal = Reader.ReadInt32(); - - for (int Index = 0; Index < Count; Index++) - { - long GpFifoHdr = Reader.ReadInt64(); - - long GpuAddr = GpFifoHdr & 0xffffffffff; - - int Size = (int)(GpFifoHdr >> 40) & 0x7ffffc; - - long CpuAddr = Context.Ns.Gpu.GetCpuAddr(GpuAddr); - - if (CpuAddr != -1) - { - byte[] Data = AMemoryHelper.ReadBytes(Context.Memory, CpuAddr, Size); - - NsGpuPBEntry[] PushBuffer = NvGpuPushBuffer.Decode(Data); - - Context.Ns.Gpu.Fifo.PushBuffer(Context.Memory, PushBuffer); - } - } - - Writer.WriteInt32(0); - Writer.WriteInt32(0); - - return 0; - } - - private long NvMapIoctlChannelAllocObjCtx(ServiceCtx Context) - { - long Position = Context.Request.GetSendBuffPtr(); - - int ClassNum = Context.Memory.ReadInt32(Position + 0); - int Flags = Context.Memory.ReadInt32(Position + 4); - - Context.Memory.WriteInt32(Position + 8, 0); - - return 0; - } - - private long NvMapIoctlChannelZcullBind(ServiceCtx Context) - { - long Position = Context.Request.GetSendBuffPtr(); - - MemReader Reader = new MemReader(Context.Memory, Position); - - long GpuVa = Reader.ReadInt64(); - int Mode = Reader.ReadInt32(); - int Padding = Reader.ReadInt32(); - - return 0; - } - - private long NvMapIoctlChannelSetErrorNotifier(ServiceCtx Context) - { - long Position = Context.Request.GetSendBuffPtr(); - - MemReader Reader = new MemReader(Context.Memory, Position); - - long Offset = Reader.ReadInt64(); - long Size = Reader.ReadInt64(); - int Mem = Reader.ReadInt32(); - int Padding = Reader.ReadInt32(); - - return 0; - } - - private long NvMapIoctlChannelSetPriority(ServiceCtx Context) - { - long Position = Context.Request.GetSendBuffPtr(); - - int Priority = Context.Memory.ReadInt32(Position); - - return 0; - } - - private long NvMapIoctlChannelAllocGpFifoEx2(ServiceCtx Context) - { - long Position = Context.Request.GetSendBuffPtr(); - - MemReader Reader = new MemReader(Context.Memory, Position); - MemWriter Writer = new MemWriter(Context.Memory, Position + 0xc); - - int Count = Reader.ReadInt32(); - int Flags = Reader.ReadInt32(); - int Unknown8 = Reader.ReadInt32(); - long Fence = Reader.ReadInt64(); - int Unknown14 = Reader.ReadInt32(); - int Unknown18 = Reader.ReadInt32(); - - Writer.WriteInt32(0); - Writer.WriteInt32(0); - - return 0; - } - - private long NvMapIocCreate(ServiceCtx Context) - { - long Position = Context.Request.GetSendBuffPtr(); - - int Size = Context.Memory.ReadInt32(Position); - - NvMap Map = new NvMap() { Size = Size }; - - Map.Handle = NvMaps.Add(Context.Process, Map); - - Map.Id = NvMapsById.Add(Context.Process, Map); - - Context.Memory.WriteInt32(Position + 4, Map.Handle); - - Context.Ns.Log.PrintInfo(LogClass.ServiceNv, $"NvMap {Map.Id} created with size {Size:x8}!"); - - return 0; - } - - private long NvMapIocFromId(ServiceCtx Context) - { - long Position = Context.Request.GetSendBuffPtr(); - - int Id = Context.Memory.ReadInt32(Position); - - NvMap Map = NvMapsById.GetData(Context.Process, Id); - - if (Map == null) - { - Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Invalid NvMap Id {Id}!"); - - return -1; //TODO: Corrent error code. - } - - Context.Memory.WriteInt32(Position + 4, Map.Handle); - - return 0; - } - - private long NvMapIocAlloc(ServiceCtx Context) - { - long Position = Context.Request.GetSendBuffPtr(); - - MemReader Reader = new MemReader(Context.Memory, Position); - - int Handle = Reader.ReadInt32(); - int HeapMask = Reader.ReadInt32(); - int Flags = Reader.ReadInt32(); - int Align = Reader.ReadInt32(); - byte Kind = (byte)Reader.ReadInt64(); - long Addr = Reader.ReadInt64(); - - NvMap Map = NvMaps.GetData(Context.Process, Handle); - - if (Map == null) - { - Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Invalid NvMap Handle {Handle}!"); - - return -1; //TODO: Corrent error code. - } - - Map.CpuAddress = Addr; - Map.Align = Align; - Map.Kind = Kind; - - return 0; - } - - private long NvMapIocFree(ServiceCtx Context) - { - long Position = Context.Request.GetSendBuffPtr(); - - MemReader Reader = new MemReader(Context.Memory, Position); - MemWriter Writer = new MemWriter(Context.Memory, Position + 8); - - int Handle = Reader.ReadInt32(); - int Padding = Reader.ReadInt32(); - - NvMap Map = NvMaps.GetData(Context.Process, Handle); - - if (Map == null) - { - Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Invalid NvMap Handle {Handle}!"); - - return -1; //TODO: Corrent error code. - } - - Writer.WriteInt64(0); - Writer.WriteInt32(Map.Size); - Writer.WriteInt32(0); - - return 0; - } - - private long NvMapIocParam(ServiceCtx Context) - { - long Position = Context.Request.GetSendBuffPtr(); - - MemReader Reader = new MemReader(Context.Memory, Position); - - int Handle = Reader.ReadInt32(); - int Param = Reader.ReadInt32(); - - NvMap Map = NvMaps.GetData(Context.Process, Handle); - - if (Map == null) - { - Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Invalid NvMap Handle {Handle}!"); - - return -1; //TODO: Corrent error code. - } - - int Response = 0; - - switch (Param) - { - case 1: Response = Map.Size; break; - case 2: Response = Map.Align; break; - case 4: Response = 0x40000000; break; - case 5: Response = Map.Kind; break; - } - - Context.Memory.WriteInt32(Position + 8, Response); - - return 0; - } - - private long NvMapIocGetId(ServiceCtx Context) - { - long Position = Context.Request.GetSendBuffPtr(); - - int Handle = Context.Memory.ReadInt32(Position + 4); - - NvMap Map = NvMaps.GetData(Context.Process, Handle); - - if (Map == null) - { - Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Invalid NvMap Handle {Handle}!"); - - return -1; //TODO: Corrent error code. - } - - Context.Memory.WriteInt32(Position, Map.Id); - - return 0; - } - public void Dispose() { Dispose(true); diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvGpuAS/NvGpuASAllocSpace.cs b/Ryujinx.Core/OsHle/Services/Nv/NvGpuAS/NvGpuASAllocSpace.cs new file mode 100644 index 0000000000..7e652d1fcb --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Nv/NvGpuAS/NvGpuASAllocSpace.cs @@ -0,0 +1,11 @@ +namespace Ryujinx.Core.OsHle.Services.Nv.NvGpuAS +{ + struct NvGpuASAllocSpace + { + public int Pages; + public int PageSize; + public int Flags; + public int Padding; + public long Offset; + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvGpuAS/NvGpuASIoctl.cs b/Ryujinx.Core/OsHle/Services/Nv/NvGpuAS/NvGpuASIoctl.cs new file mode 100644 index 0000000000..17953b7f11 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Nv/NvGpuAS/NvGpuASIoctl.cs @@ -0,0 +1,208 @@ +using ChocolArm64.Memory; +using Ryujinx.Core.Gpu; +using Ryujinx.Core.Logging; +using Ryujinx.Core.OsHle.Services.Nv.NvMap; +using System; +using System.Collections.Concurrent; + +namespace Ryujinx.Core.OsHle.Services.Nv.NvGpuAS +{ + class NvGpuASIoctl + { + private const int FlagFixedOffset = 1; + + private static ConcurrentDictionary Vmms; + + static NvGpuASIoctl() + { + Vmms = new ConcurrentDictionary(); + } + + public static int ProcessIoctl(ServiceCtx Context, int Cmd) + { + switch (Cmd & 0xffff) + { + case 0x4101: return BindChannel (Context); + case 0x4102: return AllocSpace (Context); + case 0x4103: return FreeSpace (Context); + case 0x4105: return UnmapBuffer (Context); + case 0x4106: return MapBufferEx (Context); + case 0x4108: return GetVaRegions(Context); + case 0x4109: return InitializeEx(Context); + } + + throw new NotImplementedException(Cmd.ToString("x8")); + } + + private static int BindChannel(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21Position(); + long OutputPosition = Context.Request.GetBufferType0x22Position(); + + Context.Ns.Log.PrintStub(LogClass.ServiceNv, "Stubbed."); + + return NvResult.Success; + } + + private static int AllocSpace(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21Position(); + long OutputPosition = Context.Request.GetBufferType0x22Position(); + + NvGpuASAllocSpace Args = AMemoryHelper.Read(Context.Memory, InputPosition); + + NvGpuVmm Vmm = GetVmm(Context); + + ulong Size = (ulong)Args.Pages * + (ulong)Args.PageSize; + + if ((Args.Flags & FlagFixedOffset) != 0) + { + Args.Offset = Vmm.Reserve(Args.Offset, (long)Size, 1); + } + else + { + Args.Offset = Vmm.Reserve((long)Size, 1); + } + + int Result = NvResult.Success; + + if (Args.Offset < 0) + { + Args.Offset = 0; + + Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"No memory to allocate size {Size:x16}!"); + + Result = NvResult.OutOfMemory; + } + + AMemoryHelper.Write(Context.Memory, OutputPosition, Args); + + return Result; + } + + private static int FreeSpace(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21Position(); + long OutputPosition = Context.Request.GetBufferType0x22Position(); + + NvGpuASAllocSpace Args = AMemoryHelper.Read(Context.Memory, InputPosition); + + NvGpuVmm Vmm = GetVmm(Context); + + ulong Size = (ulong)Args.Pages * + (ulong)Args.PageSize; + + Vmm.Free(Args.Offset, (long)Size); + + return NvResult.Success; + } + + private static int UnmapBuffer(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21Position(); + long OutputPosition = Context.Request.GetBufferType0x22Position(); + + NvGpuASUnmapBuffer Args = AMemoryHelper.Read(Context.Memory, InputPosition); + + NvGpuVmm Vmm = GetVmm(Context); + + /*if (!Vmm.Unmap(Args.Offset)) + { + Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Invalid buffer offset {Args.Offset:x16}!"); + }*/ + + return NvResult.Success; + } + + private static int MapBufferEx(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21Position(); + long OutputPosition = Context.Request.GetBufferType0x22Position(); + + NvGpuASMapBufferEx Args = AMemoryHelper.Read(Context.Memory, InputPosition); + + NvGpuVmm Vmm = GetVmm(Context); + + NvMapHandle Map = NvMapIoctl.GetNvMapWithFb(Context, Args.NvMapHandle); + + long PA = Map.Address + Args.BufferOffset; + + long Size = Args.MappingSize; + + if (Size == 0) + { + Size = Map.Size; + } + + Size = Map.Size; + + int Result = NvResult.Success; + + //Note: When the fixed offset flag is not set, + //the Offset field holds the alignment size instead. + if ((Args.Flags & FlagFixedOffset) != 0) + { + long MapEnd = Args.Offset + Args.MappingSize; + + if ((ulong)MapEnd <= (ulong)Args.Offset) + { + Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Offset 0x{Args.Offset:x16} and size 0x{Args.MappingSize:x16} results in a overflow!"); + + return NvResult.InvalidInput; + } + + if ((Args.Offset & NvGpuVmm.PageMask) != 0) + { + Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Offset 0x{Args.Offset:x16} is not page aligned!"); + + return NvResult.InvalidInput; + } + + Args.Offset = Vmm.Map(PA, Args.Offset, Size); + } + else + { + Args.Offset = Vmm.Map(PA, Size); + + if (Args.Offset < 0) + { + Args.Offset = 0; + + Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"No memory to map size {Args.MappingSize:x16}!"); + + Result = NvResult.InvalidInput; + } + } + + AMemoryHelper.Write(Context.Memory, OutputPosition, Args); + + return Result; + } + + private static int GetVaRegions(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21Position(); + long OutputPosition = Context.Request.GetBufferType0x22Position(); + + Context.Ns.Log.PrintStub(LogClass.ServiceNv, "Stubbed."); + + return NvResult.Success; + } + + private static int InitializeEx(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21Position(); + long OutputPosition = Context.Request.GetBufferType0x22Position(); + + Context.Ns.Log.PrintStub(LogClass.ServiceNv, "Stubbed."); + + return NvResult.Success; + } + + public static NvGpuVmm GetVmm(ServiceCtx Context) + { + return Vmms.GetOrAdd(Context.Process, (Key) => new NvGpuVmm(Context.Memory)); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvGpuAS/NvGpuASMapBufferEx.cs b/Ryujinx.Core/OsHle/Services/Nv/NvGpuAS/NvGpuASMapBufferEx.cs new file mode 100644 index 0000000000..b8bdd70691 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Nv/NvGpuAS/NvGpuASMapBufferEx.cs @@ -0,0 +1,13 @@ +namespace Ryujinx.Core.OsHle.Services.Nv.NvGpuAS +{ + struct NvGpuASMapBufferEx + { + public int Flags; + public int Kind; + public int NvMapHandle; + public int PageSize; + public long BufferOffset; + public long MappingSize; + public long Offset; + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvGpuAS/NvGpuASUnmapBuffer.cs b/Ryujinx.Core/OsHle/Services/Nv/NvGpuAS/NvGpuASUnmapBuffer.cs new file mode 100644 index 0000000000..8b62751176 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Nv/NvGpuAS/NvGpuASUnmapBuffer.cs @@ -0,0 +1,7 @@ +namespace Ryujinx.Core.OsHle.Services.Nv.NvGpuAS +{ + struct NvGpuASUnmapBuffer + { + public long Offset; + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvHostChannel/NvHostChannelIoctl.cs b/Ryujinx.Core/OsHle/Services/Nv/NvHostChannel/NvHostChannelIoctl.cs new file mode 100644 index 0000000000..4483a5defe --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Nv/NvHostChannel/NvHostChannelIoctl.cs @@ -0,0 +1,125 @@ +using ChocolArm64.Memory; +using Ryujinx.Core.Logging; +using Ryujinx.Core.OsHle.Services.Nv.NvGpuAS; +using Ryujinx.Core.Gpu; +using System; + +namespace Ryujinx.Core.OsHle.Services.Nv.NvHostChannel +{ + class NvHostChannelIoctl + { + public static int ProcessIoctl(ServiceCtx Context, int Cmd) + { + switch (Cmd & 0xffff) + { + case 0x4714: return SetUserData (Context); + case 0x4801: return SetNvMap (Context); + case 0x4808: return SubmitGpfifo (Context); + case 0x4809: return AllocObjCtx (Context); + case 0x480b: return ZcullBind (Context); + case 0x480c: return SetErrorNotifier(Context); + case 0x480d: return SetPriority (Context); + case 0x481a: return AllocGpfifoEx2 (Context); + } + + throw new NotImplementedException(Cmd.ToString("x8")); + } + + private static int SetUserData(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21Position(); + long OutputPosition = Context.Request.GetBufferType0x22Position(); + + Context.Ns.Log.PrintStub(LogClass.ServiceNv, "Stubbed."); + + return NvResult.Success; + } + + private static int SetNvMap(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21Position(); + long OutputPosition = Context.Request.GetBufferType0x22Position(); + + Context.Ns.Log.PrintStub(LogClass.ServiceNv, "Stubbed."); + + return NvResult.Success; + } + + private static int SubmitGpfifo(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21Position(); + long OutputPosition = Context.Request.GetBufferType0x22Position(); + + NvHostChannelSubmitGpfifo Args = AMemoryHelper.Read(Context.Memory, InputPosition); + + NvGpuVmm Vmm = NvGpuASIoctl.GetVmm(Context); + + for (int Index = 0; Index < Args.NumEntries; Index++) + { + long Gpfifo = Context.Memory.ReadInt64(InputPosition + 0x18 + Index * 8); + + long VA = Gpfifo & 0xffffffffff; + + int Size = (int)(Gpfifo >> 40) & 0x7ffffc; + + byte[] Data = Vmm.ReadBytes(VA, Size); + + NvGpuPBEntry[] PushBuffer = NvGpuPushBuffer.Decode(Data); + + Context.Ns.Gpu.Fifo.PushBuffer(Vmm, PushBuffer); + } + + return NvResult.Success; + } + + private static int AllocObjCtx(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21Position(); + long OutputPosition = Context.Request.GetBufferType0x22Position(); + + Context.Ns.Log.PrintStub(LogClass.ServiceNv, "Stubbed."); + + return NvResult.Success; + } + + private static int ZcullBind(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21Position(); + long OutputPosition = Context.Request.GetBufferType0x22Position(); + + Context.Ns.Log.PrintStub(LogClass.ServiceNv, "Stubbed."); + + return NvResult.Success; + } + + private static int SetErrorNotifier(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21Position(); + long OutputPosition = Context.Request.GetBufferType0x22Position(); + + Context.Ns.Log.PrintStub(LogClass.ServiceNv, "Stubbed."); + + return NvResult.Success; + } + + private static int SetPriority(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21Position(); + long OutputPosition = Context.Request.GetBufferType0x22Position(); + + Context.Ns.Log.PrintStub(LogClass.ServiceNv, "Stubbed."); + + return NvResult.Success; + } + + private static int AllocGpfifoEx2(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21Position(); + long OutputPosition = Context.Request.GetBufferType0x22Position(); + + Context.Ns.Log.PrintStub(LogClass.ServiceNv, "Stubbed."); + + return NvResult.Success; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvHostChannel/NvHostChannelSubmitGpfifo.cs b/Ryujinx.Core/OsHle/Services/Nv/NvHostChannel/NvHostChannelSubmitGpfifo.cs new file mode 100644 index 0000000000..4698a3da25 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Nv/NvHostChannel/NvHostChannelSubmitGpfifo.cs @@ -0,0 +1,11 @@ +namespace Ryujinx.Core.OsHle.Services.Nv.NvHostChannel +{ + struct NvHostChannelSubmitGpfifo + { + public long Gpfifo; + public int NumEntries; + public int Flags; + public int SyncptId; + public int SyncptValue; + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlIoctl.cs b/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlIoctl.cs index 6e8b428f55..b5703b29e8 100644 --- a/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlIoctl.cs +++ b/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlIoctl.cs @@ -1,37 +1,58 @@ using ChocolArm64.Memory; using Ryujinx.Core.Logging; +using System; using System.Collections.Concurrent; using System.Threading; -namespace Ryujinx.Core.OsHle.Services.Nv +namespace Ryujinx.Core.OsHle.Services.Nv.NvHostCtrl { class NvHostCtrlIoctl { + private const int LocksCount = 16; + private const int EventsCount = 64; private static ConcurrentDictionary EventArrays; - private static ConcurrentDictionary NvSyncPts; + private static ConcurrentDictionary NvSyncPts; static NvHostCtrlIoctl() { EventArrays = new ConcurrentDictionary(); - NvSyncPts = new ConcurrentDictionary(); + NvSyncPts = new ConcurrentDictionary(); } - private int SyncPtRead(ServiceCtx Context) + public static int ProcessIoctl(ServiceCtx Context, int Cmd) { - return SyncPtReadMinOrMax(Context, Max: false); + switch (Cmd & 0xffff) + { + case 0x0014: return SyncptRead (Context); + case 0x0015: return SyncptIncr (Context); + case 0x0016: return SyncptWait (Context); + case 0x0019: return SyncptWaitEx (Context); + case 0x001a: return SyncptReadMax (Context); + case 0x001b: return GetConfig (Context); + case 0x001d: return EventWait (Context); + case 0x001e: return EventWaitAsync(Context); + case 0x001f: return EventRegister (Context); + } + + throw new NotImplementedException(Cmd.ToString("x8")); } - private int SyncPtIncr(ServiceCtx Context) + private static int SyncptRead(ServiceCtx Context) + { + return SyncptReadMinOrMax(Context, Max: false); + } + + private static int SyncptIncr(ServiceCtx Context) { long InputPosition = Context.Request.GetBufferType0x21Position(); int Id = Context.Memory.ReadInt32(InputPosition); - if ((uint)Id >= NvHostSyncPt.SyncPtsCount) + if ((uint)Id >= NvHostSyncpt.SyncPtsCount) { return NvResult.InvalidInput; } @@ -41,39 +62,68 @@ namespace Ryujinx.Core.OsHle.Services.Nv return NvResult.Success; } - private int SyncPtWait(ServiceCtx Context) + private static int SyncptWait(ServiceCtx Context) { - return SyncPtWait(Context, Extended: false); + return SyncptWait(Context, Extended: false); } - private int SyncPtWaitEx(ServiceCtx Context) + private static int SyncptWaitEx(ServiceCtx Context) { - return SyncPtWait(Context, Extended: true); + return SyncptWait(Context, Extended: true); } - private int SyncPtReadMax(ServiceCtx Context) + private static int SyncptReadMax(ServiceCtx Context) { - return SyncPtReadMinOrMax(Context, Max: true); + return SyncptReadMinOrMax(Context, Max: true); } - private int EventWait(ServiceCtx Context) - { - return EventWait(Context, Async: false); - } - - private int EventWaitAsync(ServiceCtx Context) - { - return EventWait(Context, Async: true); - } - - private int SyncPtReadMinOrMax(ServiceCtx Context, bool Max) + private static int GetConfig(ServiceCtx Context) { long InputPosition = Context.Request.GetBufferType0x21Position(); long OutputPosition = Context.Request.GetBufferType0x22Position(); - NvHostCtrlSyncPtRead Args = AMemoryHelper.Read(Context.Memory, InputPosition); + string Nv = AMemoryHelper.ReadAsciiString(Context.Memory, InputPosition + 0, 0x41); + string Name = AMemoryHelper.ReadAsciiString(Context.Memory, InputPosition + 0x41, 0x41); - if ((uint)Args.Id >= NvHostSyncPt.SyncPtsCount) + Context.Memory.WriteByte(OutputPosition + 0x82, 0); + + Context.Ns.Log.PrintStub(LogClass.ServiceNv, "Stubbed."); + + return NvResult.Success; + } + + private static int EventWait(ServiceCtx Context) + { + return EventWait(Context, Async: false); + } + + private static int EventWaitAsync(ServiceCtx Context) + { + return EventWait(Context, Async: true); + } + + private static int EventRegister(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21Position(); + long OutputPosition = Context.Request.GetBufferType0x22Position(); + + int EventId = Context.Memory.ReadInt32(InputPosition); + + Context.Ns.Log.PrintInfo(LogClass.ServiceNv, EventId.ToString()); + + Context.Ns.Log.PrintStub(LogClass.ServiceNv, "Stubbed."); + + return NvResult.Success; + } + + private static int SyncptReadMinOrMax(ServiceCtx Context, bool Max) + { + long InputPosition = Context.Request.GetBufferType0x21Position(); + long OutputPosition = Context.Request.GetBufferType0x22Position(); + + NvHostCtrlSyncptRead Args = AMemoryHelper.Read(Context.Memory, InputPosition); + + if ((uint)Args.Id >= NvHostSyncpt.SyncPtsCount) { return NvResult.InvalidInput; } @@ -92,16 +142,16 @@ namespace Ryujinx.Core.OsHle.Services.Nv return NvResult.Success; } - private int SyncPtWait(ServiceCtx Context, bool Extended) + private static int SyncptWait(ServiceCtx Context, bool Extended) { long InputPosition = Context.Request.GetBufferType0x21Position(); long OutputPosition = Context.Request.GetBufferType0x22Position(); - NvHostCtrlSyncPtWait Args = AMemoryHelper.Read(Context.Memory, InputPosition); + NvHostCtrlSyncptWait Args = AMemoryHelper.Read(Context.Memory, InputPosition); - NvHostSyncPt SyncPt = GetSyncPt(Context); + NvHostSyncpt SyncPt = GetSyncPt(Context); - if ((uint)Args.Id >= NvHostSyncPt.SyncPtsCount) + if ((uint)Args.Id >= NvHostSyncpt.SyncPtsCount) { return NvResult.InvalidInput; } @@ -147,9 +197,9 @@ namespace Ryujinx.Core.OsHle.Services.Nv { Result = NvResult.TimedOut; } - - Context.Ns.Log.PrintDebug(LogClass.ServiceNv, "Resuming..."); } + + Context.Ns.Log.PrintDebug(LogClass.ServiceNv, "Resuming..."); } if (Extended) @@ -160,42 +210,49 @@ namespace Ryujinx.Core.OsHle.Services.Nv return Result; } - private int EventWait(ServiceCtx Context, bool Async) + private static int EventWait(ServiceCtx Context, bool Async) { long InputPosition = Context.Request.GetBufferType0x21Position(); long OutputPosition = Context.Request.GetBufferType0x22Position(); - int Result; + NvHostCtrlSyncptWaitEx Args = AMemoryHelper.Read(Context.Memory, InputPosition); - NvHostCtrlSyncPtWaitEx Args = AMemoryHelper.Read(Context.Memory, InputPosition); - - if ((uint)Args.Id >= NvHostSyncPt.SyncPtsCount) + if ((uint)Args.Id >= NvHostSyncpt.SyncPtsCount) { return NvResult.InvalidInput; } - NvHostSyncPt SyncPt = GetSyncPt(Context); + void WriteArgs() + { + AMemoryHelper.Write(Context.Memory, OutputPosition, Args); + } + + NvHostSyncpt SyncPt = GetSyncPt(Context); if (SyncPt.MinCompare(Args.Id, Args.Thresh)) { Args.Value = SyncPt.GetMin(Args.Id); + WriteArgs(); + return NvResult.Success; } + if (!Async) + { + Args.Value = 0; + } + if (Args.Timeout == 0) { - if (!Async) - { - Args.Value = 0; - } + WriteArgs(); return NvResult.TryAgain; } NvHostEvent Event; - int EventIndex; + int Result, EventIndex; if (Async) { @@ -213,35 +270,43 @@ namespace Ryujinx.Core.OsHle.Services.Nv Event = GetFreeEvent(Context, SyncPt, Args.Id, out EventIndex); } - if (Event == null) + if (Event != null && + (Event.State == NvHostEventState.Registered || + Event.State == NvHostEventState.Free)) { - return NvResult.InvalidInput; - } + Event.Id = Args.Id; + Event.Thresh = Args.Thresh; - Event.Id = Args.Id; - Event.Thresh = Args.Thresh; + Event.State = NvHostEventState.Waiting; - Event.State = NvHostEventState.Waiting; + if (!Async) + { + Args.Value = ((Args.Id & 0xfff) << 16) | 0x10000000; + } + else + { + Args.Value = Args.Id << 4; + } - if (!Async) - { - Args.Value = ((Args.Id & 0xfff) << 16) | 0x10000000; + Args.Value |= EventIndex; + + Result = NvResult.TryAgain; } else { - Args.Value = Args.Id << 4; + Result = NvResult.InvalidInput; } - Args.Value |= EventIndex; - - Result = NvResult.TryAgain; - - AMemoryHelper.Write(Context.Memory, OutputPosition, Args); + WriteArgs(); return Result; } - private NvHostEvent GetFreeEvent(ServiceCtx Context, NvHostSyncPt SyncPt, int Id, out int EventIndex) + private static NvHostEvent GetFreeEvent( + ServiceCtx Context, + NvHostSyncpt SyncPt, + int Id, + out int EventIndex) { NvHostEvent[] Events = GetEvents(Context); @@ -287,9 +352,9 @@ namespace Ryujinx.Core.OsHle.Services.Nv return null; } - public static NvHostSyncPt GetSyncPt(ServiceCtx Context) + public static NvHostSyncpt GetSyncPt(ServiceCtx Context) { - return NvSyncPts.GetOrAdd(Context.Process, (Key) => new NvHostSyncPt()); + return NvSyncPts.GetOrAdd(Context.Process, (Key) => new NvHostSyncpt()); } private static NvHostEvent[] GetEvents(ServiceCtx Context) diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtRead.cs b/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtRead.cs index 438712290a..0b05e63aa2 100644 --- a/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtRead.cs +++ b/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtRead.cs @@ -1,6 +1,6 @@ -namespace Ryujinx.Core.OsHle.Services.Nv +namespace Ryujinx.Core.OsHle.Services.Nv.NvHostCtrl { - struct NvHostCtrlSyncPtRead + struct NvHostCtrlSyncptRead { public int Id; public int Value; diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtWait.cs b/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtWait.cs index 83e62526ec..6746090ab9 100644 --- a/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtWait.cs +++ b/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtWait.cs @@ -1,6 +1,6 @@ -namespace Ryujinx.Core.OsHle.Services.Nv +namespace Ryujinx.Core.OsHle.Services.Nv.NvHostCtrl { - struct NvHostCtrlSyncPtWait + struct NvHostCtrlSyncptWait { public int Id; public int Thresh; diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtWaitEx.cs b/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtWaitEx.cs index 2d3dfd92b9..21ba378321 100644 --- a/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtWaitEx.cs +++ b/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtWaitEx.cs @@ -1,6 +1,6 @@ -namespace Ryujinx.Core.OsHle.Services.Nv +namespace Ryujinx.Core.OsHle.Services.Nv.NvHostCtrl { - struct NvHostCtrlSyncPtWaitEx + struct NvHostCtrlSyncptWaitEx { public int Id; public int Thresh; diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostEvent.cs b/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostEvent.cs index 884c8e1d61..027e25b0c1 100644 --- a/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostEvent.cs +++ b/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostEvent.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.Core.OsHle.Services.Nv +namespace Ryujinx.Core.OsHle.Services.Nv.NvHostCtrl { class NvHostEvent { diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostEventState.cs b/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostEventState.cs index dd3fe23a38..a4bd2cb6ba 100644 --- a/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostEventState.cs +++ b/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostEventState.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.Core.OsHle.Services.Nv +namespace Ryujinx.Core.OsHle.Services.Nv.NvHostCtrl { enum NvHostEventState { diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostSyncPt.cs b/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostSyncPt.cs index 3231409ca5..f49cfa3b68 100644 --- a/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostSyncPt.cs +++ b/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostSyncPt.cs @@ -3,20 +3,20 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Threading; -namespace Ryujinx.Core.OsHle.Services.Nv +namespace Ryujinx.Core.OsHle.Services.Nv.NvHostCtrl { - class NvHostSyncPt + class NvHostSyncpt { public const int SyncPtsCount = 192; - public int[] CounterMin; - public int[] CounterMax; + private int[] CounterMin; + private int[] CounterMax; private long EventMask; private ConcurrentDictionary Waiters; - public NvHostSyncPt() + public NvHostSyncpt() { CounterMin = new int[SyncPtsCount]; CounterMax = new int[SyncPtsCount]; @@ -36,7 +36,10 @@ namespace Ryujinx.Core.OsHle.Services.Nv public int Increment(int Id) { - Interlocked.Increment(ref CounterMax[Id]); + if (((EventMask >> Id) & 1) != 0) + { + Interlocked.Increment(ref CounterMax[Id]); + } return IncrementMin(Id); } diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrlGpu/NvHostCtrlGpuCharacteristics.cs b/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrlGpu/NvHostCtrlGpuCharacteristics.cs new file mode 100644 index 0000000000..ba0e7a5b0e --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrlGpu/NvHostCtrlGpuCharacteristics.cs @@ -0,0 +1,43 @@ +namespace Ryujinx.Core.OsHle.Services.Nv.NvHostCtrlGpu +{ + struct NvHostCtrlGpuCharacteristics + { + public long BufferSize; + public long BufferAddress; + public int Arch; + public int Impl; + public int Rev; + public int NumGpc; + public long L2CacheSize; + public long OnBoardVideoMemorySize; + public int NumTpcPerGpc; + public int BusType; + public int BigPageSize; + public int CompressionPageSize; + public int PdeCoverageBitCount; + public int AvailableBigPageSizes; + public int GpcMask; + public int SmArchSmVersion; + public int SmArchSpaVersion; + public int SmArchWarpCount; + public int GpuVaBitCount; + public int Reserved; + public long Flags; + public int TwodClass; + public int ThreedClass; + public int ComputeClass; + public int GpfifoClass; + public int InlineToMemoryClass; + public int DmaCopyClass; + public int MaxFbpsCount; + public int FbpEnMask; + public int MaxLtcPerFbp; + public int MaxLtsPerLtc; + public int MaxTexPerTpc; + public int MaxGpcCount; + public int RopL2EnMask0; + public int RopL2EnMask1; + public long ChipName; + public long GrCompbitStoreBaseHw; + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrlGpu/NvHostCtrlGpuIoctl.cs b/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrlGpu/NvHostCtrlGpuIoctl.cs new file mode 100644 index 0000000000..f0c8df4fc4 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrlGpu/NvHostCtrlGpuIoctl.cs @@ -0,0 +1,124 @@ +using ChocolArm64.Memory; +using Ryujinx.Core.Logging; +using System; + +namespace Ryujinx.Core.OsHle.Services.Nv.NvHostCtrlGpu +{ + class NvHostCtrlGpuIoctl + { + public static int ProcessIoctl(ServiceCtx Context, int Cmd) + { + switch (Cmd & 0xffff) + { + case 0x4701: return ZcullGetCtxSize (Context); + case 0x4702: return ZcullGetInfo (Context); + case 0x4703: return ZbcSetTable (Context); + case 0x4705: return GetCharacteristics(Context); + case 0x4706: return GetTpcMasks (Context); + case 0x4714: return GetActiveSlotMask (Context); + } + + throw new NotImplementedException(Cmd.ToString("x8")); + } + + private static int ZcullGetCtxSize(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21Position(); + long OutputPosition = Context.Request.GetBufferType0x22Position(); + + Context.Ns.Log.PrintStub(LogClass.ServiceNv, "Stubbed."); + + return NvResult.Success; + } + + private static int ZcullGetInfo(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21Position(); + long OutputPosition = Context.Request.GetBufferType0x22Position(); + + Context.Ns.Log.PrintStub(LogClass.ServiceNv, "Stubbed."); + + return NvResult.Success; + } + + private static int ZbcSetTable(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21Position(); + long OutputPosition = Context.Request.GetBufferType0x22Position(); + + Context.Ns.Log.PrintStub(LogClass.ServiceNv, "Stubbed."); + + return NvResult.Success; + } + + private static int GetCharacteristics(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21Position(); + long OutputPosition = Context.Request.GetBufferType0x22Position(); + + NvHostCtrlGpuCharacteristics Args = AMemoryHelper.Read(Context.Memory, InputPosition); + + Args.BufferSize = 0xa0; + + Args.Arch = 0x120; + Args.Impl = 0xb; + Args.Rev = 0xa1; + Args.NumGpc = 0x1; + Args.L2CacheSize = 0x40000; + Args.OnBoardVideoMemorySize = 0x0; + Args.NumTpcPerGpc = 0x2; + Args.BusType = 0x20; + Args.BigPageSize = 0x20000; + Args.CompressionPageSize = 0x20000; + Args.PdeCoverageBitCount = 0x1b; + Args.AvailableBigPageSizes = 0x30000; + Args.GpcMask = 0x1; + Args.SmArchSmVersion = 0x503; + Args.SmArchSpaVersion = 0x503; + Args.SmArchWarpCount = 0x80; + Args.GpuVaBitCount = 0x28; + Args.Reserved = 0x0; + Args.Flags = 0x55; + Args.TwodClass = 0x902d; + Args.ThreedClass = 0xb197; + Args.ComputeClass = 0xb1c0; + Args.GpfifoClass = 0xb06f; + Args.InlineToMemoryClass = 0xa140; + Args.DmaCopyClass = 0xb0b5; + Args.MaxFbpsCount = 0x1; + Args.FbpEnMask = 0x0; + Args.MaxLtcPerFbp = 0x2; + Args.MaxLtsPerLtc = 0x1; + Args.MaxTexPerTpc = 0x0; + Args.MaxGpcCount = 0x1; + Args.RopL2EnMask0 = 0x21d70; + Args.RopL2EnMask1 = 0x0; + Args.ChipName = 0x6230326d67; + Args.GrCompbitStoreBaseHw = 0x0; + + AMemoryHelper.Write(Context.Memory, OutputPosition, Args); + + return NvResult.Success; + } + + private static int GetTpcMasks(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21Position(); + long OutputPosition = Context.Request.GetBufferType0x22Position(); + + Context.Ns.Log.PrintStub(LogClass.ServiceNv, "Stubbed."); + + return NvResult.Success; + } + + private static int GetActiveSlotMask(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21Position(); + long OutputPosition = Context.Request.GetBufferType0x22Position(); + + Context.Ns.Log.PrintStub(LogClass.ServiceNv, "Stubbed."); + + return NvResult.Success; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvMap.cs b/Ryujinx.Core/OsHle/Services/Nv/NvMap.cs deleted file mode 100644 index 1bc9bb4352..0000000000 --- a/Ryujinx.Core/OsHle/Services/Nv/NvMap.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System.Threading; - -namespace Ryujinx.Core.OsHle.Services.Nv -{ - class NvMap - { - public int Handle; - public int Id; - public int Size; - public int Align; - public int Kind; - public long CpuAddress; - public long GpuAddress; - - private long m_RefCount; - - public long RefCount => m_RefCount; - - public NvMap() - { - m_RefCount = 1; - } - - public NvMap(int Size) : this() - { - this.Size = Size; - } - - public long IncrementRefCount() - { - return Interlocked.Increment(ref m_RefCount); - } - - public long DecrementRefCount() - { - return Interlocked.Decrement(ref m_RefCount); - } - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvMapAlloc.cs b/Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapAlloc.cs similarity index 81% rename from Ryujinx.Core/OsHle/Services/Nv/NvMapAlloc.cs rename to Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapAlloc.cs index b87ed2464d..86e4c23811 100644 --- a/Ryujinx.Core/OsHle/Services/Nv/NvMapAlloc.cs +++ b/Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapAlloc.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.Core.OsHle.Services.Nv +namespace Ryujinx.Core.OsHle.Services.Nv.NvMap { struct NvMapAlloc { diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvMapCreate.cs b/Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapCreate.cs similarity index 65% rename from Ryujinx.Core/OsHle/Services/Nv/NvMapCreate.cs rename to Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapCreate.cs index d69ce0887d..7d35731ce5 100644 --- a/Ryujinx.Core/OsHle/Services/Nv/NvMapCreate.cs +++ b/Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapCreate.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.Core.OsHle.Services.Nv +namespace Ryujinx.Core.OsHle.Services.Nv.NvMap { struct NvMapCreate { diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvMapFree.cs b/Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapFree.cs similarity index 78% rename from Ryujinx.Core/OsHle/Services/Nv/NvMapFree.cs rename to Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapFree.cs index dcb87a35b4..ee8bc618a6 100644 --- a/Ryujinx.Core/OsHle/Services/Nv/NvMapFree.cs +++ b/Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapFree.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.Core.OsHle.Services.Nv +namespace Ryujinx.Core.OsHle.Services.Nv.NvMap { struct NvMapFree { diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvMapFromId.cs b/Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapFromId.cs similarity index 65% rename from Ryujinx.Core/OsHle/Services/Nv/NvMapFromId.cs rename to Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapFromId.cs index 77f48ee1ff..377eaa7f02 100644 --- a/Ryujinx.Core/OsHle/Services/Nv/NvMapFromId.cs +++ b/Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapFromId.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.Core.OsHle.Services.Nv +namespace Ryujinx.Core.OsHle.Services.Nv.NvMap { struct NvMapFromId { diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvMapGetId.cs b/Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapGetId.cs similarity index 64% rename from Ryujinx.Core/OsHle/Services/Nv/NvMapGetId.cs rename to Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapGetId.cs index dfabc09521..639a5fb4c6 100644 --- a/Ryujinx.Core/OsHle/Services/Nv/NvMapGetId.cs +++ b/Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapGetId.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.Core.OsHle.Services.Nv +namespace Ryujinx.Core.OsHle.Services.Nv.NvMap { struct NvMapGetId { diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapHandle.cs b/Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapHandle.cs new file mode 100644 index 0000000000..4a021f6f35 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapHandle.cs @@ -0,0 +1,37 @@ +using System.Threading; + +namespace Ryujinx.Core.OsHle.Services.Nv.NvMap +{ + class NvMapHandle + { + public int Handle; + public int Id; + public int Size; + public int Align; + public int Kind; + public long Address; + public bool Allocated; + + private long Dupes; + + public NvMapHandle() + { + Dupes = 1; + } + + public NvMapHandle(int Size) : this() + { + this.Size = Size; + } + + public long IncrementRefCount() + { + return Interlocked.Increment(ref Dupes); + } + + public long DecrementRefCount() + { + return Interlocked.Decrement(ref Dupes); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapHandleParam.cs b/Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapHandleParam.cs new file mode 100644 index 0000000000..80ff4c0347 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapHandleParam.cs @@ -0,0 +1,12 @@ +namespace Ryujinx.Core.OsHle.Services.Nv.NvMap +{ + enum NvMapHandleParam + { + Size = 1, + Align = 2, + Base = 3, + Heap = 4, + Kind = 5, + Compr = 6 + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapIoctl.cs b/Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapIoctl.cs new file mode 100644 index 0000000000..cf1eeb06d2 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapIoctl.cs @@ -0,0 +1,283 @@ +using ChocolArm64.Memory; +using Ryujinx.Core.Logging; +using Ryujinx.Core.OsHle.Utilities; +using Ryujinx.Core.Gpu; +using System.Collections.Concurrent; + +namespace Ryujinx.Core.OsHle.Services.Nv.NvMap +{ + class NvMapIoctl + { + private const int FlagNotFreedYet = 1; + + private static ConcurrentDictionary NvMaps; + + static NvMapIoctl() + { + NvMaps = new ConcurrentDictionary(); + } + + public static int ProcessIoctl(ServiceCtx Context, int Cmd) + { + switch (Cmd & 0xffff) + { + case 0x0101: return Create(Context); + case 0x0103: return FromId(Context); + case 0x0104: return Alloc (Context); + case 0x0105: return Free (Context); + case 0x0109: return Param (Context); + case 0x010e: return GetId (Context); + } + + Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Unsupported Ioctl command 0x{Cmd:x8}!"); + + return NvResult.NotSupported; + } + + private static int Create(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21Position(); + long OutputPosition = Context.Request.GetBufferType0x22Position(); + + NvMapCreate Args = AMemoryHelper.Read(Context.Memory, InputPosition); + + if (Args.Size == 0) + { + return NvResult.InvalidInput; + } + + int Size = IntUtils.RoundUp(Args.Size, NvGpuVmm.PageSize); + + Args.Handle = AddNvMap(Context, new NvMapHandle(Size)); + + Context.Ns.Log.PrintInfo(LogClass.ServiceNv, $"Created map {Args.Handle} with size 0x{Size:x8}!"); + + AMemoryHelper.Write(Context.Memory, OutputPosition, Args); + + return NvResult.Success; + } + + private static int FromId(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21Position(); + long OutputPosition = Context.Request.GetBufferType0x22Position(); + + NvMapFromId Args = AMemoryHelper.Read(Context.Memory, InputPosition); + + NvMapHandle Map = GetNvMap(Context, Args.Id); + + if (Map == null) + { + return NvResult.InvalidInput; + } + + Map.IncrementRefCount(); + + Args.Handle = Args.Id; + + AMemoryHelper.Write(Context.Memory, OutputPosition, Args); + + return NvResult.Success; + } + + private static int Alloc(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21Position(); + long OutputPosition = Context.Request.GetBufferType0x22Position(); + + NvMapAlloc Args = AMemoryHelper.Read(Context.Memory, InputPosition); + + NvMapHandle Map = GetNvMap(Context, Args.Handle); + + if (Map == null) + { + return NvResult.InvalidInput; + } + + if ((Args.Align & (Args.Align - 1)) != 0) + { + return NvResult.InvalidInput; + } + + if ((uint)Args.Align < NvGpuVmm.PageSize) + { + Args.Align = NvGpuVmm.PageSize; + } + + int Result = NvResult.Success; + + if (!Map.Allocated) + { + Map.Allocated = true; + + Map.Align = Args.Align; + Map.Kind = (byte)Args.Kind; + + int Size = IntUtils.RoundUp(Map.Size, NvGpuVmm.PageSize); + + long Address = Args.Address; + + if (Address == 0) + { + //When the address is zero, we need to allocate + //our own backing memory for the NvMap. + if (!Context.Ns.Os.Allocator.TryAllocate((uint)Size, out Address)) + { + Result = NvResult.OutOfMemory; + } + } + + if (Result == NvResult.Success) + { + Map.Size = Size; + Map.Address = Address; + } + } + + AMemoryHelper.Write(Context.Memory, OutputPosition, Args); + + return Result; + } + + private static int Free(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21Position(); + long OutputPosition = Context.Request.GetBufferType0x22Position(); + + NvMapFree Args = AMemoryHelper.Read(Context.Memory, InputPosition); + + NvMapHandle Map = GetNvMap(Context, Args.Handle); + + if (Map == null) + { + return NvResult.InvalidInput; + } + + long RefCount = Map.DecrementRefCount(); + + if (RefCount <= 0) + { + DeleteNvMap(Context, Args.Handle); + + Context.Ns.Log.PrintInfo(LogClass.ServiceNv, $"Deleted map {Args.Handle}!"); + + Args.Flags = 0; + } + else + { + Args.Flags = FlagNotFreedYet; + } + + Args.RefCount = RefCount; + Args.Size = Map.Size; + + AMemoryHelper.Write(Context.Memory, OutputPosition, Args); + + return NvResult.Success; + } + + private static int Param(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21Position(); + long OutputPosition = Context.Request.GetBufferType0x22Position(); + + NvMapParam Args = AMemoryHelper.Read(Context.Memory, InputPosition); + + NvMapHandle Map = GetNvMap(Context, Args.Handle); + + if (Map == null) + { + return NvResult.InvalidInput; + } + + switch ((NvMapHandleParam)Args.Param) + { + case NvMapHandleParam.Size: Args.Result = Map.Size; break; + case NvMapHandleParam.Align: Args.Result = Map.Align; break; + case NvMapHandleParam.Heap: Args.Result = 0x40000000; break; + case NvMapHandleParam.Kind: Args.Result = Map.Kind; break; + case NvMapHandleParam.Compr: Args.Result = 0; break; + + //Note: Base is not supported and returns an error. + //Any other value also returns an error. + default: return NvResult.InvalidInput; + } + + AMemoryHelper.Write(Context.Memory, OutputPosition, Args); + + return NvResult.Success; + } + + private static int GetId(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21Position(); + long OutputPosition = Context.Request.GetBufferType0x22Position(); + + NvMapGetId Args = AMemoryHelper.Read(Context.Memory, InputPosition); + + NvMapHandle Map = GetNvMap(Context, Args.Handle); + + if (Map == null) + { + return NvResult.InvalidInput; + } + + Args.Id = Args.Handle; + + AMemoryHelper.Write(Context.Memory, OutputPosition, Args); + + return NvResult.Success; + } + + private static int AddNvMap(ServiceCtx Context, NvMapHandle Map) + { + IdDictionary Maps = NvMaps.GetOrAdd(Context.Process, (Key) => + { + IdDictionary Dict = new IdDictionary(); + + Dict.Add(0, new NvMapHandle()); + + return Dict; + }); + + return Maps.Add(Map); + } + + private static bool DeleteNvMap(ServiceCtx Context, int Handle) + { + if (NvMaps.TryGetValue(Context.Process, out IdDictionary Maps)) + { + return Maps.Delete(Handle) != null; + } + + return false; + } + + public static void InitializeNvMap(ServiceCtx Context) + { + IdDictionary Maps = NvMaps.GetOrAdd(Context.Process, (Key) =>new IdDictionary()); + + Maps.Add(0, new NvMapHandle()); + } + + public static NvMapHandle GetNvMapWithFb(ServiceCtx Context, int Handle) + { + if (NvMaps.TryGetValue(Context.Process, out IdDictionary Maps)) + { + return Maps.GetData(Handle); + } + + return null; + } + + public static NvMapHandle GetNvMap(ServiceCtx Context, int Handle) + { + if (Handle != 0 && NvMaps.TryGetValue(Context.Process, out IdDictionary Maps)) + { + return Maps.GetData(Handle); + } + + return null; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvMapParam.cs b/Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapParam.cs similarity index 71% rename from Ryujinx.Core/OsHle/Services/Nv/NvMapParam.cs rename to Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapParam.cs index c41142055d..196ef6aba8 100644 --- a/Ryujinx.Core/OsHle/Services/Nv/NvMapParam.cs +++ b/Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapParam.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.Core.OsHle.Services.Nv +namespace Ryujinx.Core.OsHle.Services.Nv.NvMap { struct NvMapParam { diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvMapFb.cs b/Ryujinx.Core/OsHle/Services/Nv/NvMapFb.cs deleted file mode 100644 index d8a47418b9..0000000000 --- a/Ryujinx.Core/OsHle/Services/Nv/NvMapFb.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace Ryujinx.Core.OsHle.Services.Nv -{ - class NvMapFb - { - private List BufferOffs; - - public NvMapFb() - { - BufferOffs = new List(); - } - - public void AddBufferOffset(long Offset) - { - BufferOffs.Add(Offset); - } - - public bool HasBufferOffset(int Index) - { - if ((uint)Index >= BufferOffs.Count) - { - return false; - } - - return true; - } - - public long GetBufferOffset(int Index) - { - if ((uint)Index >= BufferOffs.Count) - { - throw new ArgumentOutOfRangeException(nameof(Index)); - } - - return BufferOffs[Index]; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvMapIoctl.cs b/Ryujinx.Core/OsHle/Services/Nv/NvMapIoctl.cs deleted file mode 100644 index 7a022b65bf..0000000000 --- a/Ryujinx.Core/OsHle/Services/Nv/NvMapIoctl.cs +++ /dev/null @@ -1,238 +0,0 @@ -using ChocolArm64.Memory; -using Ryujinx.Graphics.Gpu; -using System.Collections.Concurrent; - -namespace Ryujinx.Core.OsHle.Services.Nv -{ - class NvMapIoctl - { - private NsGpuMemoryMgr Vmm; - - private static ConcurrentDictionary NvMaps; - - private object NvMapLock; - - private const int FlagNotFreedYet = 1; - - private enum NvMapParam - { - Size = 1, - Align = 2, - Base = 3, - Heap = 4, - Kind = 5, - Compr = 6 - } - - public NvMapIoctl() - { - NvMapLock = new object(); - } - - public int Create(ServiceCtx Context) - { - long InputPosition = Context.Request.GetBufferType0x21Position(); - long OutputPosition = Context.Request.GetBufferType0x22Position(); - - NvMapCreate Args = AMemoryHelper.Read(Context.Memory, InputPosition); - - if (Args.Size == 0) - { - return NvResult.InvalidInput; - } - - Args.Handle = AddNvMap(Context, new NvMap(Args.Size)); - - AMemoryHelper.Write(Context.Memory, OutputPosition, Args); - - return NvResult.Success; - } - - public int IocFromId(ServiceCtx Context) - { - long InputPosition = Context.Request.GetBufferType0x21Position(); - long OutputPosition = Context.Request.GetBufferType0x22Position(); - - NvMapFromId Args = AMemoryHelper.Read(Context.Memory, InputPosition); - - lock (NvMapLock) - { - NvMap Map = GetNvMap(Context, Args.Id); - - if (Map == null) - { - return NvResult.InvalidInput; - } - - Map.IncrementRefCount(); - } - - AMemoryHelper.Write(Context.Memory, OutputPosition, Args); - - return NvResult.Success; - } - - public int Alloc(ServiceCtx Context) - { - long InputPosition = Context.Request.GetBufferType0x21Position(); - long OutputPosition = Context.Request.GetBufferType0x22Position(); - - NvMapAlloc Args = AMemoryHelper.Read(Context.Memory, InputPosition); - - NvMap Map = GetNvMap(Context, Args.Handle); - - if (Map == null) - { - return NvResult.InvalidInput; - } - - if ((Args.Align & (Args.Align - 1)) != 0) - { - return NvResult.InvalidInput; - } - - if ((uint)Args.Align < 0x1000) - { - Args.Align = 0x1000; - } - - Map.Align = Args.Align; - - Map.Kind = (byte)Args.Kind; - - Args.Address = Vmm.Reserve(Args.Address, (uint)Map.Size, (uint)Map.Align); - - AMemoryHelper.Write(Context.Memory, OutputPosition, Args); - - return NvResult.Success; - } - - public int Free(ServiceCtx Context) - { - long InputPosition = Context.Request.GetBufferType0x21Position(); - long OutputPosition = Context.Request.GetBufferType0x22Position(); - - NvMapFree Args = AMemoryHelper.Read(Context.Memory, InputPosition); - - lock (NvMapLock) - { - NvMap Map = GetNvMap(Context, Args.Handle); - - if (Map == null) - { - return NvResult.InvalidInput; - } - - long RefCount = Map.DecrementRefCount(); - - if (RefCount <= 0) - { - DeleteNvMap(Context, Args.Handle); - - Args.Flags = 0; - } - else - { - Args.Flags = FlagNotFreedYet; - } - - Args.RefCount = RefCount; - Args.Size = Map.Size; - } - - AMemoryHelper.Write(Context.Memory, OutputPosition, Args); - - return NvResult.Success; - } - - public int Param(ServiceCtx Context) - { - long InputPosition = Context.Request.GetBufferType0x21Position(); - long OutputPosition = Context.Request.GetBufferType0x22Position(); - - Nv.NvMapParam Args = AMemoryHelper.Read(Context.Memory, InputPosition); - - NvMap Map = GetNvMap(Context, Args.Handle); - - if (Map == null) - { - return NvResult.InvalidInput; - } - - switch ((NvMapParam)Args.Param) - { - case NvMapParam.Size: Args.Result = Map.Size; break; - case NvMapParam.Align: Args.Result = Map.Align; break; - case NvMapParam.Heap: Args.Result = 0x40000000; break; - case NvMapParam.Kind: Args.Result = Map.Kind; break; - case NvMapParam.Compr: Args.Result = 0; break; - - //Note: Base is not supported and returns an error. - //Any other value also returns an error. - default: return NvResult.InvalidInput; - } - - AMemoryHelper.Write(Context.Memory, OutputPosition, Args); - - return NvResult.Success; - } - - public int GetId(ServiceCtx Context) - { - long InputPosition = Context.Request.GetBufferType0x21Position(); - long OutputPosition = Context.Request.GetBufferType0x22Position(); - - NvMapGetId Args = AMemoryHelper.Read(Context.Memory, InputPosition); - - NvMap Map = GetNvMap(Context, Args.Handle); - - if (Map == null) - { - return NvResult.InvalidInput; - } - - Args.Id = Args.Handle; - - AMemoryHelper.Write(Context.Memory, OutputPosition, Args); - - return NvResult.Success; - } - - private int AddNvMap(ServiceCtx Context, NvMap Map) - { - IdDictionary Maps = NvMaps.GetOrAdd(Context.Process, (Key) => new IdDictionary()); - - return Maps.Add(Map); - } - - private bool DeleteNvMap(ServiceCtx Context, int Handle) - { - if (NvMaps.TryGetValue(Context.Process, out IdDictionary Maps)) - { - return Maps.Delete(Handle) != null; - } - - return false; - } - - public NvMap GetNvMapWithFb(ServiceCtx Context, int Handle) - { - if (NvMaps.TryGetValue(Context.Process, out IdDictionary Maps)) - { - return Maps.GetData(Handle); - } - - return null; - } - - public NvMap GetNvMap(ServiceCtx Context, int Handle) - { - if (Handle != 0 && NvMaps.TryGetValue(Context.Process, out IdDictionary Maps)) - { - return Maps.GetData(Handle); - } - - return null; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvResult.cs b/Ryujinx.Core/OsHle/Services/Nv/NvResult.cs index f145c475cf..5a41916512 100644 --- a/Ryujinx.Core/OsHle/Services/Nv/NvResult.cs +++ b/Ryujinx.Core/OsHle/Services/Nv/NvResult.cs @@ -7,6 +7,7 @@ namespace Ryujinx.Core.OsHle.Services.Nv public const int OutOfMemory = -12; public const int InvalidInput = -22; public const int NotSupported = -25; + public const int Restart = -85; public const int TimedOut = -110; } } \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Vi/NvFlinger.cs b/Ryujinx.Core/OsHle/Services/Vi/NvFlinger.cs index 5aa3c3d51e..1b1e6c1d16 100644 --- a/Ryujinx.Core/OsHle/Services/Vi/NvFlinger.cs +++ b/Ryujinx.Core/OsHle/Services/Vi/NvFlinger.cs @@ -1,9 +1,9 @@ using ChocolArm64.Memory; +using Ryujinx.Core.Gpu; using Ryujinx.Core.Logging; using Ryujinx.Core.OsHle.Handles; -using Ryujinx.Core.OsHle.Services.Nv; +using Ryujinx.Core.OsHle.Services.Nv.NvMap; using Ryujinx.Graphics.Gal; -using Ryujinx.Graphics.Gpu; using System; using System.Collections.Generic; using System.IO; @@ -282,20 +282,11 @@ namespace Ryujinx.Core.OsHle.Services.Android int FbWidth = 1280; int FbHeight = 720; - NvMap Map = GetNvMap(Context, Slot); + NvMapHandle Map = GetNvMap(Context, Slot); - NvMapFb MapFb = (NvMapFb)INvDrvServices.NvMapsFb.GetData(Context.Process, 0); + NvMapHandle MapFb = NvMapIoctl.GetNvMapWithFb(Context, 0); - long CpuAddr = Map.CpuAddress; - long GpuAddr = Map.GpuAddress; - - if (MapFb.HasBufferOffset(Slot)) - { - CpuAddr += MapFb.GetBufferOffset(Slot); - - //TODO: Enable once the frame buffers problems are fixed. - //GpuAddr += MapFb.GetBufferOffset(Slot); - } + long FbAddr = Map.Address + MapFb.Address; BufferQueue[Slot].State = BufferState.Acquired; @@ -352,17 +343,17 @@ namespace Ryujinx.Core.OsHle.Services.Android //TODO: Support double buffering here aswell, it is broken for GPU //frame buffers because it seems to be completely out of sync. - if (Context.Ns.Gpu.Engine3d.IsFrameBufferPosition(GpuAddr)) + if (Context.Ns.Gpu.Engine3d.IsFrameBufferPosition(FbAddr)) { //Frame buffer is rendered to by the GPU, we can just //bind the frame buffer texture, it's not necessary to read anything. - Renderer.SetFrameBuffer(GpuAddr); + Renderer.SetFrameBuffer(FbAddr); } else { //Frame buffer is not set on the GPU registers, in this case //assume that the app is manually writing to it. - Texture Texture = new Texture(CpuAddr, FbWidth, FbHeight); + Texture Texture = new Texture(FbAddr, FbWidth, FbHeight); byte[] Data = TextureReader.Read(Context.Memory, Texture); @@ -372,7 +363,7 @@ namespace Ryujinx.Core.OsHle.Services.Android Context.Ns.Gpu.Renderer.QueueAction(() => ReleaseBuffer(Slot)); } - private NvMap GetNvMap(ServiceCtx Context, int Slot) + private NvMapHandle GetNvMap(ServiceCtx Context, int Slot) { int NvMapHandle = BitConverter.ToInt32(BufferQueue[Slot].Data.RawData, 0x4c); @@ -385,7 +376,7 @@ namespace Ryujinx.Core.OsHle.Services.Android NvMapHandle = BitConverter.ToInt32(RawValue, 0); } - return INvDrvServices.NvMaps.GetData(Context.Process, NvMapHandle); + return NvMapIoctl.GetNvMap(Context, NvMapHandle); } private void ReleaseBuffer(int Slot) diff --git a/Ryujinx.Core/OsHle/Utilities/IntUtils.cs b/Ryujinx.Core/OsHle/Utilities/IntUtils.cs new file mode 100644 index 0000000000..4a522465ac --- /dev/null +++ b/Ryujinx.Core/OsHle/Utilities/IntUtils.cs @@ -0,0 +1,15 @@ +namespace Ryujinx.Core.OsHle.Utilities +{ + static class IntUtils + { + public static int RoundUp(int Value, int Size) + { + return (Value + (Size - 1)) & ~(Size - 1); + } + + public static long RoundUp(long Value, int Size) + { + return (Value + (Size - 1)) & ~((long)Size - 1); + } + } +} diff --git a/Ryujinx.Core/Switch.cs b/Ryujinx.Core/Switch.cs index 02fdc8b696..a755ea0c74 100644 --- a/Ryujinx.Core/Switch.cs +++ b/Ryujinx.Core/Switch.cs @@ -4,7 +4,7 @@ using Ryujinx.Core.Logging; using Ryujinx.Core.OsHle; using Ryujinx.Core.Settings; using Ryujinx.Graphics.Gal; -using Ryujinx.Graphics.Gpu; +using Ryujinx.Core.Gpu; using System; namespace Ryujinx.Core @@ -15,7 +15,7 @@ namespace Ryujinx.Core public Logger Log { get; private set; } - internal NsGpu Gpu { get; private set; } + internal NvGpu Gpu { get; private set; } internal VirtualFileSystem VFs { get; private set; } @@ -45,7 +45,7 @@ namespace Ryujinx.Core Log = new Logger(); - Gpu = new NsGpu(Renderer); + Gpu = new NvGpu(Renderer); VFs = new VirtualFileSystem(); diff --git a/Ryujinx.Graphics/Gpu/INvGpuEngine.cs b/Ryujinx.Graphics/Gpu/INvGpuEngine.cs deleted file mode 100644 index 17e9b435c8..0000000000 --- a/Ryujinx.Graphics/Gpu/INvGpuEngine.cs +++ /dev/null @@ -1,11 +0,0 @@ -using ChocolArm64.Memory; - -namespace Ryujinx.Graphics.Gpu -{ - interface INvGpuEngine - { - int[] Registers { get; } - - void CallMethod(AMemory Memory, NsGpuPBEntry PBEntry); - } -} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gpu/NsGpuMemoryMgr.cs b/Ryujinx.Graphics/Gpu/NsGpuMemoryMgr.cs deleted file mode 100644 index eff5178313..0000000000 --- a/Ryujinx.Graphics/Gpu/NsGpuMemoryMgr.cs +++ /dev/null @@ -1,212 +0,0 @@ -namespace Ryujinx.Graphics.Gpu -{ - public class NsGpuMemoryMgr - { - private const long AddrSize = 1L << 40; - - private const int PTLvl0Bits = 14; - private const int PTLvl1Bits = 14; - private const int PTPageBits = 12; - - private const int PTLvl0Size = 1 << PTLvl0Bits; - private const int PTLvl1Size = 1 << PTLvl1Bits; - private const int PageSize = 1 << PTPageBits; - - private const int PTLvl0Mask = PTLvl0Size - 1; - private const int PTLvl1Mask = PTLvl1Size - 1; - private const int PageMask = PageSize - 1; - - private const int PTLvl0Bit = PTPageBits + PTLvl1Bits; - private const int PTLvl1Bit = PTPageBits; - - private const long PteUnmapped = -1; - private const long PteReserved = -2; - - private long[][] PageTable; - - public NsGpuMemoryMgr() - { - PageTable = new long[PTLvl0Size][]; - } - - public long Map(long CpuAddr, long GpuAddr, long Size) - { - CpuAddr &= ~PageMask; - GpuAddr &= ~PageMask; - - for (long Offset = 0; Offset < Size; Offset += PageSize) - { - if (GetPTAddr(GpuAddr + Offset) != PteReserved) - { - return Map(CpuAddr, Size); - } - } - - for (long Offset = 0; Offset < Size; Offset += PageSize) - { - SetPTAddr(GpuAddr + Offset, CpuAddr + Offset); - } - - return GpuAddr; - } - - public void Unmap(long Position, long Size) - { - for (long Offset = 0; Offset < Size; Offset += PageSize) - { - SetPTAddr(Position + Offset, PteUnmapped); - } - } - - public long Map(long CpuAddr, long Size) - { - CpuAddr &= ~PageMask; - - long Position = GetFreePosition(Size); - - if (Position != -1) - { - for (long Offset = 0; Offset < Size; Offset += PageSize) - { - SetPTAddr(Position + Offset, CpuAddr + Offset); - } - } - - return Position; - } - - public long Reserve(long GpuAddr, long Size, long Align) - { - for (long Offset = 0; Offset < Size; Offset += PageSize) - { - if (HasPTAddr(GpuAddr + Offset)) - { - return Reserve(Size, Align); - } - } - - for (long Offset = 0; Offset < Size; Offset += PageSize) - { - SetPTAddr(GpuAddr + Offset, PteReserved); - } - - return GpuAddr; - } - - public long Reserve(long Size, long Align) - { - long Position = GetFreePosition(Size, Align); - - if (Position != -1) - { - for (long Offset = 0; Offset < Size; Offset += PageSize) - { - SetPTAddr(Position + Offset, PteReserved); - } - } - - return Position; - } - - private long GetFreePosition(long Size, long Align = 1) - { - long Position = 0; - long FreeSize = 0; - - if (Align < 1) - { - Align = 1; - } - - Align = (Align + PageMask) & ~PageMask; - - while (Position + FreeSize < AddrSize) - { - if (!HasPTAddr(Position + FreeSize)) - { - FreeSize += PageSize; - - if (FreeSize >= Size) - { - return Position; - } - } - else - { - Position += FreeSize + PageSize; - FreeSize = 0; - - long Remainder = Position % Align; - - if (Remainder != 0) - { - Position = (Position - Remainder) + Align; - } - } - } - - return -1; - } - - public long GetCpuAddr(long Position) - { - long BasePos = GetPTAddr(Position); - - if (BasePos < 0) - { - return -1; - } - - return BasePos + (Position & PageMask); - } - - private bool HasPTAddr(long Position) - { - if (Position >> PTLvl0Bits + PTLvl1Bits + PTPageBits != 0) - { - return false; - } - - long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask; - long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask; - - if (PageTable[L0] == null) - { - return false; - } - - return PageTable[L0][L1] != PteUnmapped; - } - - private long GetPTAddr(long Position) - { - long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask; - long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask; - - if (PageTable[L0] == null) - { - return -1; - } - - return PageTable[L0][L1]; - } - - private void SetPTAddr(long Position, long TgtAddr) - { - long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask; - long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask; - - if (PageTable[L0] == null) - { - PageTable[L0] = new long[PTLvl1Size]; - - for (int Index = 0; Index < PTLvl1Size; Index++) - { - PageTable[L0][Index] = PteUnmapped; - } - } - - PageTable[L0][L1] = TgtAddr; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gpu/NvGpuMethod.cs b/Ryujinx.Graphics/Gpu/NvGpuMethod.cs deleted file mode 100644 index 2923ddff0c..0000000000 --- a/Ryujinx.Graphics/Gpu/NvGpuMethod.cs +++ /dev/null @@ -1,6 +0,0 @@ -using ChocolArm64.Memory; - -namespace Ryujinx.Graphics.Gpu -{ - delegate void NvGpuMethod(AMemory Memory, NsGpuPBEntry PBEntry); -} \ No newline at end of file