public void CallMethod(NvGpuVmm vmm, GpuMethodCall methCall) { if (_methods.TryGetValue(methCall.Method, out NvGpuMethod method)) { method(vmm, methCall); } else { WriteRegister(methCall); } }
public bool MemoryRegionModified(NvGpuVmm Vmm, long Position, long Size, NvGpuBufferType Type) { HashSet <long> Uploaded = UploadedKeys[(int)Type]; if (!Uploaded.Add(Position)) { return(false); } return(Vmm.IsRegionModified(Position, Size, Type)); }
private bool TryReuse(NvGpuVmm Vmm, long Position, GalImage NewImage) { if (Gpu.Renderer.Texture.TryGetImage(Position, out GalImage CachedImage) && CachedImage.SizeMatches(NewImage)) { Gpu.Renderer.RenderTarget.Reinterpret(Position, NewImage); return(true); } return(false); }
public void CallMethod(NvGpuVmm Vmm, GpuMethodCall MethCall) { if (Methods.TryGetValue(MethCall.Method, out NvGpuMethod Method)) { Method(Vmm, MethCall); } else { WriteRegister(MethCall); } }
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 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); }
internal void CopyPlanes(NvGpuVmm vmm, SurfaceOutputConfig outputConfig) { switch (outputConfig.PixelFormat) { case SurfacePixelFormat.Rgba8: CopyPlanesRgba8(vmm, outputConfig); break; case SurfacePixelFormat.Yuv420P: CopyPlanesYuv420P(vmm, outputConfig); break; default: ThrowUnimplementedPixelFormat(outputConfig.PixelFormat); break; } }
private (long, GalImage, GalTextureSampler) UploadTexture(NvGpuVmm vmm, int textureHandle) { if (textureHandle == 0) { //FIXME: Some games like puyo puyo will use handles with the value 0. //This is a bug, most likely caused by sync issues. return(0, default(GalImage), default(GalTextureSampler)); } Profile.Begin(Profiles.GPU.Engine3d.UploadTexture); bool linkedTsc = ReadRegisterBool(NvGpuEngine3dReg.LinkedTsc); int ticIndex = (textureHandle >> 0) & 0xfffff; int tscIndex = linkedTsc ? ticIndex : (textureHandle >> 20) & 0xfff; long ticPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.TexHeaderPoolOffset); long tscPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.TexSamplerPoolOffset); ticPosition += ticIndex * 0x20; tscPosition += tscIndex * 0x20; GalImage image = TextureFactory.MakeTexture(vmm, ticPosition); GalTextureSampler sampler = TextureFactory.MakeSampler(_gpu, vmm, tscPosition); long key = vmm.ReadInt64(ticPosition + 4) & 0xffffffffffff; if (image.Layout == GalMemoryLayout.BlockLinear) { key &= ~0x1ffL; } else if (image.Layout == GalMemoryLayout.Pitch) { key &= ~0x1fL; } key = vmm.GetPhysicalAddress(key); if (key == -1) { Profile.End(Profiles.GPU.Engine3d.UploadTexture); //FIXME: Shouldn't ignore invalid addresses. return(0, default(GalImage), default(GalTextureSampler)); } _gpu.ResourceManager.SendTexture(vmm, key, image); Profile.End(Profiles.GPU.Engine3d.UploadTexture); return(key, image, sampler); }
internal void CopyPlanes(NvGpuVmm Vmm, SurfaceOutputConfig OutputConfig) { switch (OutputConfig.PixelFormat) { case SurfacePixelFormat.RGBA8: CopyPlanesRgba8(Vmm, OutputConfig); break; case SurfacePixelFormat.YUV420P: CopyPlanesYuv420p(Vmm, OutputConfig); break; default: ThrowUnimplementedPixelFormat(OutputConfig.PixelFormat); break; } }
public void SendTexture(NvGpuVmm Vmm, long Position, GalImage NewImage, int TexIndex = -1) { PrepareSendTexture(Vmm, Position, NewImage); if (TexIndex >= 0) { Gpu.Renderer.Texture.Bind(Position, TexIndex, NewImage); } ImageTypes[Position] = ImageType.Texture; }
private bool TryReuse(NvGpuVmm vmm, long position, GalImage newImage) { if (_gpu.Renderer.Texture.TryGetImage(position, out GalImage cachedImage) && cachedImage.TextureTarget == newImage.TextureTarget && cachedImage.SizeMatches(newImage)) { _gpu.Renderer.RenderTarget.Reinterpret(position, newImage); return(true); } return(false); }
public bool MemoryRegionModified(NvGpuVmm vmm, long position, long size, NvGpuBufferType type) { HashSet <long> uploaded = _uploadedKeys[(int)type]; if (!uploaded.Add(position)) { return(false); } return(vmm.IsRegionModified(position, size, type)); }
private void ClearBuffers(NvGpuVmm Vmm, NvGpuPBEntry PBEntry) { int Arg0 = PBEntry.Arguments[0]; int FbIndex = (Arg0 >> 6) & 0xf; GalClearBufferFlags Flags = (GalClearBufferFlags)(Arg0 & 0x3f); SetFrameBuffer(Vmm, FbIndex); Gpu.Renderer.Rasterizer.ClearBuffers(Flags); }
public void PushCommands(NvGpuVmm vmm, int[] cmdBuffer) { List <ChCommand> commands = new List <ChCommand>(); ChClassId currentClass = 0; for (int index = 0; index < cmdBuffer.Length; index++) { int cmd = cmdBuffer[index]; int value = (cmd >> 0) & 0xffff; int methodOffset = (cmd >> 16) & 0xfff; ChSubmissionMode submissionMode = (ChSubmissionMode)((cmd >> 28) & 0xf); switch (submissionMode) { case ChSubmissionMode.SetClass: currentClass = (ChClassId)(value >> 6); break; case ChSubmissionMode.Incrementing: { int count = value; for (int argIdx = 0; argIdx < count; argIdx++) { int argument = cmdBuffer[++index]; commands.Add(new ChCommand(currentClass, methodOffset + argIdx, argument)); } break; } case ChSubmissionMode.NonIncrementing: { int count = value; int[] arguments = new int[count]; for (int argIdx = 0; argIdx < count; argIdx++) { arguments[argIdx] = cmdBuffer[++index]; } commands.Add(new ChCommand(currentClass, methodOffset, arguments)); break; } } } ProcessCommands(vmm, commands.ToArray()); }
public static GalImage MakeTexture(NvGpuVmm Vmm, long TicPosition) { int[] Tic = ReadWords(Vmm, TicPosition, 8); GalImageFormat Format = GetImageFormat(Tic); 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); TextureSwizzle Swizzle = (TextureSwizzle)((Tic[2] >> 21) & 7); GalMemoryLayout Layout; if (Swizzle == TextureSwizzle.BlockLinear || Swizzle == TextureSwizzle.BlockLinearColorKey) { Layout = GalMemoryLayout.BlockLinear; } else { Layout = GalMemoryLayout.Pitch; } int BlockHeightLog2 = (Tic[3] >> 3) & 7; int TileWidthLog2 = (Tic[3] >> 10) & 7; int BlockHeight = 1 << BlockHeightLog2; int TileWidth = 1 << TileWidthLog2; int Width = (Tic[4] & 0xffff) + 1; int Height = (Tic[5] & 0xffff) + 1; GalImage Image = new GalImage( Width, Height, TileWidth, BlockHeight, Layout, Format, XSource, YSource, ZSource, WSource); if (Layout == GalMemoryLayout.Pitch) { Image.Pitch = (Tic[3] & 0xffff) << 5; } return(Image); }
private void CbData(NvGpuVmm vmm, GpuMethodCall methCall) { long position = MakeInt64From2xInt32(NvGpuEngine3dReg.ConstBufferAddress); int offset = ReadRegister(NvGpuEngine3dReg.ConstBufferOffset); vmm.WriteInt32(position + offset, methCall.Argument); WriteRegister(NvGpuEngine3dReg.ConstBufferOffset, offset + 4); _gpu.ResourceManager.ClearPbCache(NvGpuBufferType.ConstBuffer); }
public void PushCommands(NvGpuVmm Vmm, int[] CmdBuffer) { List <ChCommand> Commands = new List <ChCommand>(); ChClassId CurrentClass = 0; for (int Index = 0; Index < CmdBuffer.Length; Index++) { int Cmd = CmdBuffer[Index]; int Value = (Cmd >> 0) & 0xffff; int MethodOffset = (Cmd >> 16) & 0xfff; ChSubmissionMode SubmissionMode = (ChSubmissionMode)((Cmd >> 28) & 0xf); switch (SubmissionMode) { case ChSubmissionMode.SetClass: CurrentClass = (ChClassId)(Value >> 6); break; case ChSubmissionMode.Incrementing: { int Count = Value; for (int ArgIdx = 0; ArgIdx < Count; ArgIdx++) { int Argument = CmdBuffer[++Index]; Commands.Add(new ChCommand(CurrentClass, MethodOffset + ArgIdx, Argument)); } break; } case ChSubmissionMode.NonIncrementing: { int Count = Value; int[] Arguments = new int[Count]; for (int ArgIdx = 0; ArgIdx < Count; ArgIdx++) { Arguments[ArgIdx] = CmdBuffer[++Index]; } Commands.Add(new ChCommand(CurrentClass, MethodOffset, Arguments)); break; } } } ProcessCommands(Vmm, Commands.ToArray()); }
private static void PushGpfifo(ServiceCtx Context, NvGpuVmm Vmm, long Gpfifo) { long VA = Gpfifo & 0xff_ffff_ffff; int Size = (int)(Gpfifo >> 40) & 0x7ffffc; byte[] Data = Vmm.ReadBytes(VA, Size); NvGpuPBEntry[] PushBuffer = NvGpuPushBuffer.Decode(Data); Context.Device.Gpu.Fifo.PushBuffer(Vmm, PushBuffer); }
private void DispatchRender(NvGpuVmm Vmm, GalPipelineState State) { int IndexCount = ReadRegister(NvGpuEngine3dReg.IndexBatchCount); int PrimCtrl = ReadRegister(NvGpuEngine3dReg.VertexBeginGl); GalPrimitiveType PrimType = (GalPrimitiveType)(PrimCtrl & 0xffff); bool InstanceNext = ((PrimCtrl >> 26) & 1) != 0; bool InstanceCont = ((PrimCtrl >> 27) & 1) != 0; if (InstanceNext && InstanceCont) { throw new InvalidOperationException("GPU tried to increase and reset instance count at the same time"); } if (InstanceNext) { CurrentInstance++; } else if (!InstanceCont) { CurrentInstance = 0; } State.Instance = CurrentInstance; Gpu.Renderer.Pipeline.Bind(State); if (IndexCount != 0) { int IndexEntryFmt = ReadRegister(NvGpuEngine3dReg.IndexArrayFormat); int IndexFirst = ReadRegister(NvGpuEngine3dReg.IndexBatchFirst); int VertexBase = ReadRegister(NvGpuEngine3dReg.VertexArrayElemBase); long IndexPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.IndexArrayAddress); long IboKey = Vmm.GetPhysicalAddress(IndexPosition); Gpu.Renderer.Rasterizer.DrawElements(IboKey, IndexFirst, VertexBase, PrimType); } else { int VertexFirst = ReadRegister(NvGpuEngine3dReg.VertexArrayFirst); int VertexCount = ReadRegister(NvGpuEngine3dReg.VertexArrayCount); Gpu.Renderer.Rasterizer.DrawArrays(VertexFirst, VertexCount, PrimType); } //Is the GPU really clearing those registers after draw? WriteRegister(NvGpuEngine3dReg.IndexBatchFirst, 0); WriteRegister(NvGpuEngine3dReg.IndexBatchCount, 0); }
private bool QueryKeyUpload(NvGpuVmm Vmm, long Key, long Size, NvGpuBufferType Type) { List <long> Uploaded = UploadedKeys[(int)Type]; if (Uploaded.Contains(Key)) { return(false); } Uploaded.Add(Key); return(Vmm.IsRegionModified(Key, Size, Type)); }
public void SendZetaBuffer(NvGpuVmm Vmm, long Position, GalImage NewImage) { long Size = (uint)ImageUtils.GetSize(NewImage); ImageTypes[Position] = ImageType.ZetaBuffer; if (!TryReuse(Vmm, Position, NewImage)) { Gpu.Renderer.Texture.Create(Position, (int)Size, NewImage); } Gpu.Renderer.RenderTarget.BindZeta(Position); }
public void SendZetaBuffer(NvGpuVmm vmm, long position, GalImage newImage) { long size = (uint)ImageUtils.GetSize(newImage); _imageTypes[position] = ImageType.ZetaBuffer; if (!TryReuse(vmm, position, newImage)) { _gpu.Renderer.Texture.Create(position, (int)size, newImage); } _gpu.Renderer.RenderTarget.BindZeta(position); }
private bool IsShaderModified(NvGpuVmm Vmm, long Key) { long Address = Vmm.GetPhysicalAddress(Key); if (Gpu.Renderer.Shader.TryGetSize(Address, out long Size)) { if (!QueryKeyUpload(Vmm, Address, Size, NvGpuBufferType.Shader)) { return(false); } } return(true); }
protected NvInternalResult SubmitGpfifo(ref SubmitGpfifoArguments header, Span <long> entries) { NvGpuVmm vmm = NvHostAsGpuDeviceFile.GetAddressSpaceContext(Owner).Vmm; foreach (long entry in entries) { _gpu.Pusher.Push(vmm, entry); } header.Fence.Id = 0; header.Fence.Value = 0; return(NvInternalResult.Success); }
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 UploadTextures(NvGpuVmm vmm, GalPipelineState state, long[] keys) { Profile.Begin(Profiles.GPU.Engine3d.UploadTextures); long baseShPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.ShaderAddress); int textureCbIndex = ReadRegister(NvGpuEngine3dReg.TextureCbIndex); List <(long, GalImage, GalTextureSampler)> unboundTextures = new List <(long, GalImage, GalTextureSampler)>(); for (int index = 0; index < keys.Length; index++) { foreach (TextureDescriptor desc in _gpu.Renderer.Shader.GetTextureUsage(keys[index])) { int textureHandle; if (desc.IsBindless) { long position = _constBuffers[index][desc.CbufSlot].Position; textureHandle = vmm.ReadInt32(position + desc.CbufOffset * 4); } else { long position = _constBuffers[index][textureCbIndex].Position; textureHandle = vmm.ReadInt32(position + desc.HandleIndex * 4); } unboundTextures.Add(UploadTexture(vmm, textureHandle)); } } for (int index = 0; index < unboundTextures.Count; index++) { (long key, GalImage image, GalTextureSampler sampler) = unboundTextures[index]; if (key == 0) { continue; } _gpu.Renderer.Texture.Bind(key, index, image); _gpu.Renderer.Texture.SetSampler(image, sampler); } Profile.End(Profiles.GPU.Engine3d.UploadTextures); }
private void SetFrameBuffer(NvGpuVmm vmm, int fbIndex) { long va = MakeInt64From2xInt32(NvGpuEngine3dReg.FrameBufferNAddress + fbIndex * 0x10); int surfFormat = ReadRegister(NvGpuEngine3dReg.FrameBufferNFormat + fbIndex * 0x10); if (va == 0 || surfFormat == 0) { _gpu.Renderer.RenderTarget.UnbindColor(fbIndex); return; } long key = vmm.GetPhysicalAddress(va); int width = ReadRegister(NvGpuEngine3dReg.FrameBufferNWidth + fbIndex * 0x10); int height = ReadRegister(NvGpuEngine3dReg.FrameBufferNHeight + fbIndex * 0x10); int arrayMode = ReadRegister(NvGpuEngine3dReg.FrameBufferNArrayMode + fbIndex * 0x10); int layerCount = arrayMode & 0xFFFF; int layerStride = ReadRegister(NvGpuEngine3dReg.FrameBufferNLayerStride + fbIndex * 0x10); int baseLayer = ReadRegister(NvGpuEngine3dReg.FrameBufferNBaseLayer + fbIndex * 0x10); int blockDim = ReadRegister(NvGpuEngine3dReg.FrameBufferNBlockDim + fbIndex * 0x10); int gobBlockHeight = 1 << ((blockDim >> 4) & 7); GalMemoryLayout layout = (GalMemoryLayout)((blockDim >> 12) & 1); float tx = ReadRegisterFloat(NvGpuEngine3dReg.ViewportNTranslateX + fbIndex * 8); float ty = ReadRegisterFloat(NvGpuEngine3dReg.ViewportNTranslateY + fbIndex * 8); float sx = ReadRegisterFloat(NvGpuEngine3dReg.ViewportNScaleX + fbIndex * 8); float sy = ReadRegisterFloat(NvGpuEngine3dReg.ViewportNScaleY + fbIndex * 8); _viewportX0 = (int)MathF.Max(0, tx - MathF.Abs(sx)); _viewportY0 = (int)MathF.Max(0, ty - MathF.Abs(sy)); _viewportX1 = (int)(tx + MathF.Abs(sx)); _viewportY1 = (int)(ty + MathF.Abs(sy)); GalImageFormat format = ImageUtils.ConvertSurface((GalSurfaceFormat)surfFormat); GalImage image = new GalImage(width, height, 1, 1, 1, gobBlockHeight, 1, layout, format, GalTextureTarget.TwoD); _gpu.ResourceManager.SendColorBuffer(vmm, key, fbIndex, image); _gpu.Renderer.RenderTarget.SetViewport(fbIndex, _viewportX0, _viewportY0, _viewportX1 - _viewportX0, _viewportY1 - _viewportY0); }
private (long, GalImage, GalTextureSampler) UploadTexture(NvGpuVmm Vmm, int TextureHandle) { if (TextureHandle == 0) { //FIXME: Some games like puyo puyo will use handles with the value 0. //This is a bug, most likely caused by sync issues. return(0, default(GalImage), default(GalTextureSampler)); } bool LinkedTsc = ReadRegisterBool(NvGpuEngine3dReg.LinkedTsc); int TicIndex = (TextureHandle >> 0) & 0xfffff; int TscIndex = LinkedTsc ? TicIndex : (TextureHandle >> 20) & 0xfff; long TicPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.TexHeaderPoolOffset); long TscPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.TexSamplerPoolOffset); TicPosition += TicIndex * 0x20; TscPosition += TscIndex * 0x20; GalImage Image = TextureFactory.MakeTexture(Vmm, TicPosition); GalTextureSampler Sampler = TextureFactory.MakeSampler(Gpu, Vmm, TscPosition); long Key = Vmm.ReadInt64(TicPosition + 4) & 0xffffffffffff; if (Image.Layout == GalMemoryLayout.BlockLinear) { Key &= ~0x1ffL; } else if (Image.Layout == GalMemoryLayout.Pitch) { Key &= ~0x1fL; } Key = Vmm.GetPhysicalAddress(Key); if (Key == -1) { //FIXME: Shouldn't ignore invalid addresses. return(0, default(GalImage), default(GalTextureSampler)); } Gpu.ResourceManager.SendTexture(Vmm, Key, Image); return(Key, Image, Sampler); }
private static int FreeSpace(ServiceCtx Context) { long InputPosition = Context.Request.GetBufferType0x21().Position; long OutputPosition = Context.Request.GetBufferType0x22().Position; NvGpuASAllocSpace Args = AMemoryHelper.Read <NvGpuASAllocSpace>(Context.Memory, InputPosition); NvGpuVmm Vmm = GetVmm(Context); ulong Size = (ulong)Args.Pages * (ulong)Args.PageSize; Vmm.Free(Args.Offset, (long)Size); return(NvResult.Success); }