Beispiel #1
0
 public void CallMethod(NvGpuVmm vmm, GpuMethodCall methCall)
 {
     if (_methods.TryGetValue(methCall.Method, out NvGpuMethod method))
     {
         method(vmm, methCall);
     }
     else
     {
         WriteRegister(methCall);
     }
 }
Beispiel #2
0
        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));
        }
Beispiel #3
0
        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);
        }
Beispiel #4
0
 public void CallMethod(NvGpuVmm Vmm, GpuMethodCall MethCall)
 {
     if (Methods.TryGetValue(MethCall.Method, out NvGpuMethod Method))
     {
         Method(Vmm, MethCall);
     }
     else
     {
         WriteRegister(MethCall);
     }
 }
Beispiel #5
0
 public void CallMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
 {
     if (Methods.TryGetValue(PBEntry.Method, out NvGpuMethod Method))
     {
         Method(Vmm, PBEntry);
     }
     else
     {
         WriteRegister(PBEntry);
     }
 }
Beispiel #6
0
        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);
        }
Beispiel #7
0
        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);
        }
Beispiel #8
0
        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;
            }
        }
Beispiel #9
0
        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);
        }
Beispiel #10
0
        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;
        }
Beispiel #12
0
        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);
        }
Beispiel #13
0
        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));
        }
Beispiel #14
0
        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);
        }
Beispiel #15
0
        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());
        }
Beispiel #16
0
        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);
        }
Beispiel #17
0
        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);
        }
Beispiel #18
0
        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);
        }
Beispiel #20
0
        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);
        }
Beispiel #21
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));
        }
Beispiel #22
0
        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);
        }
Beispiel #23
0
        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);
        }
Beispiel #24
0
        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);
        }
Beispiel #25
0
        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);
        }
Beispiel #26
0
        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);
        }
Beispiel #27
0
        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);
        }
Beispiel #28
0
        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);
        }
Beispiel #29
0
        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);
        }
Beispiel #30
0
        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);
        }