public void CallMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry) { if (Methods.TryGetValue(PBEntry.Method, out NvGpuMethod Method)) { Method(Vmm, PBEntry); } else { WriteRegister(PBEntry); } }
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] = Vmm.ReadInt32(Position); } return(Words); }
private void VertexEndGl(NvGpuVmm Vmm, NvGpuPBEntry PBEntry) { SetFrameBuffer(Vmm, 0); long[] Tags = UploadShaders(Vmm); Gpu.Renderer.BindProgram(); SetAlphaBlending(); UploadTextures(Vmm, Tags); UploadUniforms(Vmm); UploadVertexArrays(Vmm); }
private void ClearBuffers(NvGpuVmm Vmm, NvGpuPBEntry PBEntry) { int Arg0 = PBEntry.Arguments[0]; int FbIndex = (Arg0 >> 6) & 0xf; int Layer = (Arg0 >> 10) & 0x3ff; GalClearBufferFlags Flags = (GalClearBufferFlags)(Arg0 & 0x3f); SetFrameBuffer(Vmm, 0); //TODO: Enable this once the frame buffer problems are fixed. //Gpu.Renderer.ClearBuffers(Layer, Flags); }
private void CbData(NvGpuVmm Vmm, NvGpuPBEntry PBEntry) { long Position = MakeInt64From2xInt32(NvGpuEngine3dReg.ConstBufferAddress); int Offset = ReadRegister(NvGpuEngine3dReg.ConstBufferOffset); foreach (int Arg in PBEntry.Arguments) { Vmm.WriteInt32(Position + Offset, Arg); Offset += 4; } WriteRegister(NvGpuEngine3dReg.ConstBufferOffset, Offset); }
private void SetFrameBuffer(NvGpuVmm Vmm, int FbIndex) { long VA = MakeInt64From2xInt32(NvGpuEngine3dReg.FrameBufferNAddress + FbIndex * 0x10); long PA = Vmm.GetPhysicalAddress(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(PA, 1280, 720); Gpu.Renderer.BindFrameBuffer(PA); }
private long[] UploadShaders(NvGpuVmm Vmm) { long[] Tags = new long[5]; long BasePosition = MakeInt64From2xInt32(NvGpuEngine3dReg.ShaderAddress); for (int Index = 0; Index < 6; Index++) { int Control = ReadRegister(NvGpuEngine3dReg.ShaderNControl + Index * 0x10); int Offset = ReadRegister(NvGpuEngine3dReg.ShaderNOffset + Index * 0x10); //Note: Vertex Program (B) is always enabled. bool Enable = (Control & 1) != 0 || Index == 1; if (!Enable) { continue; } long Tag = BasePosition + (uint)Offset; //TODO: Find a better way to calculate the size. int Size = 0x20000; byte[] Code = Vmm.ReadBytes(Tag, Size); GalShaderType ShaderType = GetTypeFromProgram(Index); Tags[(int)ShaderType] = Tag; Gpu.Renderer.CreateShader(Tag, ShaderType, Code); Gpu.Renderer.BindShader(Tag); } int RawSX = ReadRegister(NvGpuEngine3dReg.ViewportScaleX); int RawSY = ReadRegister(NvGpuEngine3dReg.ViewportScaleY); float SX = BitConverter.Int32BitsToSingle(RawSX); float SY = BitConverter.Int32BitsToSingle(RawSY); float SignX = MathF.Sign(SX); float SignY = MathF.Sign(SY); Gpu.Renderer.SetUniform2F(GalConsts.FlipUniformName, SignX, SignY); return(Tags); }
public static GalTexture MakeTexture(NvGpu Gpu, NvGpuVmm Vmm, long TicPosition) { int[] Tic = ReadWords(Vmm, TicPosition, 8); GalTextureFormat Format = (GalTextureFormat)(Tic[0] & 0x7f); GalTextureSource XSource = (GalTextureSource)((Tic[0] >> 19) & 7); GalTextureSource YSource = (GalTextureSource)((Tic[0] >> 22) & 7); GalTextureSource ZSource = (GalTextureSource)((Tic[0] >> 25) & 7); GalTextureSource WSource = (GalTextureSource)((Tic[0] >> 28) & 7); long TextureAddress = (uint)Tic[1]; TextureAddress |= (long)((ushort)Tic[2]) << 32; TextureSwizzle Swizzle = (TextureSwizzle)((Tic[2] >> 21) & 7); int Pitch = (Tic[3] & 0xffff) << 5; int BlockHeightLog2 = (Tic[3] >> 3) & 7; int BlockHeight = 1 << BlockHeightLog2; int Width = (Tic[4] & 0xffff) + 1; int Height = (Tic[5] & 0xffff) + 1; Texture Texture = new Texture( TextureAddress, Width, Height, Pitch, BlockHeight, Swizzle, Format); byte[] Data = TextureReader.Read(Vmm, Texture); return(new GalTexture( Data, Width, Height, Format, XSource, YSource, ZSource, WSource)); }
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; long Position = MakeInt64From2xInt32(NvGpuEngine3dReg.ConstBufferAddress); ConstBuffers[Stage][Index].Position = Position; ConstBuffers[Stage][Index].Enabled = Enabled; ConstBuffers[Stage][Index].Size = ReadRegister(NvGpuEngine3dReg.ConstBufferSize); }
private void QueryControl(NvGpuVmm Vmm, NvGpuPBEntry PBEntry) { long Position = MakeInt64From2xInt32(NvGpuEngine3dReg.QueryAddress); int Seq = Registers[(int)NvGpuEngine3dReg.QuerySequence]; int Ctrl = Registers[(int)NvGpuEngine3dReg.QueryControl]; int Mode = Ctrl & 3; if (Mode == 0) { //Write mode. Vmm.WriteInt32(Position, Seq); } WriteRegister(PBEntry); }
public void Execute(NvGpuVmm Vmm, long Position, int Param) { Reset(); Gprs[1] = Param; Pc = Position; FetchOpCode(Vmm); while (Step(Vmm)) { ; } //Due to the delay slot, we still need to execute //one more instruction before we actually exit. Step(Vmm); }
private void UploadTexture(NvGpuVmm Vmm, long BasePosition, int TexIndex, int HndIndex) { long Position = BasePosition + HndIndex * 4; int TextureHandle = Vmm.ReadInt32(Position); int TicIndex = (TextureHandle >> 0) & 0xfffff; int TscIndex = (TextureHandle >> 20) & 0xfff; long TicPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.TexHeaderPoolOffset); long TscPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.TexSamplerPoolOffset); TicPosition += TicIndex * 0x20; TscPosition += TscIndex * 0x20; GalTextureSampler Sampler = TextureFactory.MakeSampler(Gpu, Vmm, TscPosition); long TextureAddress = Vmm.ReadInt64(TicPosition + 4) & 0xffffffffffff; TextureAddress = Vmm.GetPhysicalAddress(TextureAddress); if (IsFrameBufferPosition(TextureAddress)) { //This texture is a frame buffer texture, //we shouldn't read anything from memory and bind //the frame buffer texture instead, since we're not //really writing anything to memory. Gpu.Renderer.BindFrameBufferTexture(TextureAddress, TexIndex, Sampler); } else { GalTexture Texture = TextureFactory.MakeTexture(Gpu, Vmm, TicPosition); Gpu.Renderer.SetTextureAndSampler(TexIndex, Texture, Sampler); Gpu.Renderer.BindTexture(TexIndex); } }
private void UploadTextures(NvGpuVmm Vmm, long[] Tags) { long BaseShPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.ShaderAddress); int TextureCbIndex = ReadRegister(NvGpuEngine3dReg.TextureCbIndex); //Note: On the emulator renderer, Texture Unit 0 is //reserved for drawing the frame buffer. int TexIndex = 1; for (int Index = 0; Index < Tags.Length; Index++) { foreach (ShaderDeclInfo DeclInfo in Gpu.Renderer.GetTextureUsage(Tags[Index])) { long Position = ConstBuffers[Index][TextureCbIndex].Position; UploadTexture(Vmm, Position, TexIndex, DeclInfo.Index); Gpu.Renderer.SetUniform1(DeclInfo.Name, TexIndex); TexIndex++; } } }
private bool Step(NvGpuVmm Vmm) { long BaseAddr = Pc - 4; FetchOpCode(Vmm); if ((OpCode & 7) < 7) { //Operation produces a value. AssignmentOperation AsgOp = (AssignmentOperation)((OpCode >> 4) & 7); int Result = GetAluResult(); switch (AsgOp) { //Fetch parameter and ignore result. case AssignmentOperation.IgnoreAndFetch: { SetDstGpr(FetchParam()); break; } //Move result. case AssignmentOperation.Move: { SetDstGpr(Result); break; } //Move result and use as Method Address. case AssignmentOperation.MoveAndSetMaddr: { SetDstGpr(Result); SetMethAddr(Result); break; } //Fetch parameter and send result. case AssignmentOperation.FetchAndSend: { SetDstGpr(FetchParam()); Send(Vmm, Result); break; } //Move and send result. case AssignmentOperation.MoveAndSend: { SetDstGpr(Result); Send(Vmm, Result); break; } //Fetch parameter and use result as Method Address. case AssignmentOperation.FetchAndSetMaddr: { SetDstGpr(FetchParam()); SetMethAddr(Result); break; } //Move result and use as Method Address, then fetch and send paramter. case AssignmentOperation.MoveAndSetMaddrThenFetchAndSend: { SetDstGpr(Result); SetMethAddr(Result); Send(Vmm, FetchParam()); break; } //Move result and use as Method Address, then send bits 17:12 of result. case AssignmentOperation.MoveAndSetMaddrThenSendHigh: { SetDstGpr(Result); SetMethAddr(Result); Send(Vmm, (Result >> 12) & 0x3f); break; } } } else { //Branch. bool OnNotZero = ((OpCode >> 4) & 1) != 0; bool Taken = OnNotZero ? GetGprA() != 0 : GetGprA() == 0; if (Taken) { Pc = BaseAddr + (GetImm() << 2); bool NoDelays = (OpCode & 0x20) != 0; if (NoDelays) { FetchOpCode(Vmm); } return(true); } } bool Exit = (OpCode & 0x80) != 0; return(!Exit); }
private void UploadVertexArrays(NvGpuVmm Vmm) { long IndexPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.IndexArrayAddress); int IndexSize = ReadRegister(NvGpuEngine3dReg.IndexArrayFormat); int IndexFirst = ReadRegister(NvGpuEngine3dReg.IndexBatchFirst); int IndexCount = ReadRegister(NvGpuEngine3dReg.IndexBatchCount); GalIndexFormat IndexFormat = (GalIndexFormat)IndexSize; IndexSize = 1 << IndexSize; if (IndexSize > 4) { throw new InvalidOperationException(); } if (IndexSize != 0) { int BufferSize = IndexCount * IndexSize; byte[] Data = Vmm.ReadBytes(IndexPosition, BufferSize); Gpu.Renderer.SetIndexArray(Data, IndexFormat); } List <GalVertexAttrib>[] Attribs = new List <GalVertexAttrib> [32]; for (int Attr = 0; Attr < 16; Attr++) { int Packed = ReadRegister(NvGpuEngine3dReg.VertexAttribNFormat + Attr); int ArrayIndex = Packed & 0x1f; if (Attribs[ArrayIndex] == null) { Attribs[ArrayIndex] = new List <GalVertexAttrib>(); } Attribs[ArrayIndex].Add(new GalVertexAttrib( Attr, ((Packed >> 6) & 0x1) != 0, (Packed >> 7) & 0x3fff, (GalVertexAttribSize)((Packed >> 21) & 0x3f), (GalVertexAttribType)((Packed >> 27) & 0x7), ((Packed >> 31) & 0x1) != 0)); } for (int Index = 0; Index < 32; Index++) { int VertexFirst = ReadRegister(NvGpuEngine3dReg.VertexArrayFirst); int VertexCount = ReadRegister(NvGpuEngine3dReg.VertexArrayCount); int Control = ReadRegister(NvGpuEngine3dReg.VertexArrayNControl + Index * 4); bool Enable = (Control & 0x1000) != 0; long VertexPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.VertexArrayNAddress + Index * 4); if (!Enable) { continue; } int Stride = Control & 0xfff; long Size = 0; if (IndexCount != 0) { Size = GetVertexCountFromIndexBuffer( Vmm, IndexPosition, IndexCount, IndexSize); } else { Size = VertexCount; } //TODO: Support cases where the Stride is 0. //In this case, we need to use the size of the attribute. Size *= Stride; byte[] Data = Vmm.ReadBytes(VertexPosition, Size); GalVertexAttrib[] AttribArray = Attribs[Index]?.ToArray() ?? new GalVertexAttrib[0]; Gpu.Renderer.SetVertexArray(Index, Stride, Data, AttribArray); int PrimCtrl = ReadRegister(NvGpuEngine3dReg.VertexBeginGl); GalPrimitiveType PrimType = (GalPrimitiveType)(PrimCtrl & 0xffff); if (IndexCount != 0) { Gpu.Renderer.DrawElements(Index, IndexFirst, PrimType); } else { Gpu.Renderer.DrawArrays(Index, VertexFirst, VertexCount, PrimType); } } }
private void CopyTexture(NvGpuVmm Vmm, Texture Texture, byte[] Buffer) { TextureWriter.Write(Vmm, Texture, Buffer); }