diff options
| author | gdkchan <gab.dark.100@gmail.com> | 2019-12-05 17:34:47 -0300 |
|---|---|---|
| committer | Thog <thog@protonmail.com> | 2020-01-09 02:13:00 +0100 |
| commit | e25b7c9848b6ec486eb513297b5c536857665c7f (patch) | |
| tree | c1ccb6c58bed0f7ece835359516330104feb8f4d /Ryujinx.Graphics.Gpu/Engine | |
| parent | 6a98c643cabeea25dc42e19fe475a687a034a532 (diff) | |
Initial support for the guest OpenGL driver (NVIDIA and Nouveau)
Diffstat (limited to 'Ryujinx.Graphics.Gpu/Engine')
| -rw-r--r-- | Ryujinx.Graphics.Gpu/Engine/Compute.cs | 2 | ||||
| -rw-r--r-- | Ryujinx.Graphics.Gpu/Engine/ComputeParams.cs | 3 | ||||
| -rw-r--r-- | Ryujinx.Graphics.Gpu/Engine/Inline2Memory.cs | 87 | ||||
| -rw-r--r-- | Ryujinx.Graphics.Gpu/Engine/MethodCopyTexture.cs | 23 | ||||
| -rw-r--r-- | Ryujinx.Graphics.Gpu/Engine/MethodUniformBufferUpdate.cs | 6 | ||||
| -rw-r--r-- | Ryujinx.Graphics.Gpu/Engine/Methods.cs | 78 |
6 files changed, 167 insertions, 32 deletions
diff --git a/Ryujinx.Graphics.Gpu/Engine/Compute.cs b/Ryujinx.Graphics.Gpu/Engine/Compute.cs index eb7c4f4a..f0daac67 100644 --- a/Ryujinx.Graphics.Gpu/Engine/Compute.cs +++ b/Ryujinx.Graphics.Gpu/Engine/Compute.cs @@ -30,7 +30,7 @@ namespace Ryujinx.Graphics.Gpu.Engine var samplerPool = state.Get<PoolState>(MethodOffset.SamplerPoolState); - _textureManager.SetComputeSamplerPool(samplerPool.Address.Pack(), samplerPool.MaximumId); + _textureManager.SetComputeSamplerPool(samplerPool.Address.Pack(), samplerPool.MaximumId, dispatchParams.SamplerIndex); var texturePool = state.Get<PoolState>(MethodOffset.TexturePoolState); diff --git a/Ryujinx.Graphics.Gpu/Engine/ComputeParams.cs b/Ryujinx.Graphics.Gpu/Engine/ComputeParams.cs index 03582f05..77e60aa4 100644 --- a/Ryujinx.Graphics.Gpu/Engine/ComputeParams.cs +++ b/Ryujinx.Graphics.Gpu/Engine/ComputeParams.cs @@ -1,3 +1,4 @@ +using Ryujinx.Graphics.Gpu.State; using System; using System.Runtime.InteropServices; @@ -32,7 +33,7 @@ namespace Ryujinx.Graphics.Gpu.Engine public int ShaderOffset; public int Unknown9; public int Unknown10; - public int Unknown11; + public SamplerIndex SamplerIndex; public int GridSizeX; public int GridSizeYZ; public int Unknown14; diff --git a/Ryujinx.Graphics.Gpu/Engine/Inline2Memory.cs b/Ryujinx.Graphics.Gpu/Engine/Inline2Memory.cs index 09de992f..8d1ebebe 100644 --- a/Ryujinx.Graphics.Gpu/Engine/Inline2Memory.cs +++ b/Ryujinx.Graphics.Gpu/Engine/Inline2Memory.cs @@ -1,5 +1,8 @@ +using Ryujinx.Common; using Ryujinx.Graphics.Gpu.State; +using Ryujinx.Graphics.Texture; using System; +using System.Runtime.InteropServices; namespace Ryujinx.Graphics.Gpu.Engine { @@ -12,6 +15,10 @@ namespace Ryujinx.Graphics.Gpu.Engine private int _offset; private int _size; + private bool _finished; + + private int[] _buffer; + public void LaunchDma(GpuState state, int argument) { _params = state.Get<Inline2MemoryParams>(MethodOffset.I2mParams); @@ -20,23 +27,91 @@ namespace Ryujinx.Graphics.Gpu.Engine _offset = 0; _size = _params.LineLengthIn * _params.LineCount; + + int count = BitUtils.DivRoundUp(_size, 4); + + if (_buffer == null || _buffer.Length < count) + { + _buffer = new int[count]; + } + + ulong dstBaseAddress = _context.MemoryManager.Translate(_params.DstAddress.Pack()); + + _context.Methods.TextureManager.Flush(dstBaseAddress, (ulong)_size); + + _finished = false; } public void LoadInlineData(GpuState state, int argument) { - if (_isLinear) + if (!_finished) { - for (int shift = 0; shift < 32 && _offset < _size; shift += 8, _offset++) - { - ulong gpuVa = _params.DstAddress.Pack() + (ulong)_offset; + _buffer[_offset++] = argument; - _context.MemoryAccessor.Write(gpuVa, new byte[] { (byte)(argument >> shift) }); + if (_offset * 4 >= _size) + { + FinishTransfer(); } } + } + + private void FinishTransfer() + { + Span<byte> data = MemoryMarshal.Cast<int, byte>(_buffer).Slice(0, _size); + + if (_isLinear && _params.LineCount == 1) + { + ulong address = _context.MemoryManager.Translate( _params.DstAddress.Pack()); + + _context.PhysicalMemory.Write(address, data); + } else { - throw new NotImplementedException(); + var dstCalculator = new OffsetCalculator( + _params.DstWidth, + _params.DstHeight, + _params.DstStride, + _isLinear, + _params.DstMemoryLayout.UnpackGobBlocksInY(), + 1); + + int srcOffset = 0; + + ulong dstBaseAddress = _context.MemoryManager.Translate(_params.DstAddress.Pack()); + + for (int y = _params.DstY; y < _params.DstY + _params.LineCount; y++) + { + int x1 = _params.DstX; + int x2 = _params.DstX + _params.LineLengthIn; + int x2Trunc = _params.DstX + BitUtils.AlignDown(_params.LineLengthIn, 16); + + int x; + + for (x = x1; x < x2Trunc; x += 16, srcOffset += 16) + { + int dstOffset = dstCalculator.GetOffset(x, y); + + ulong dstAddress = dstBaseAddress + (ulong)dstOffset; + + Span<byte> pixel = data.Slice(srcOffset, 16); + + _context.PhysicalMemory.Write(dstAddress, pixel); + } + + for (; x < x2; x++, srcOffset++) + { + int dstOffset = dstCalculator.GetOffset(x, y); + + ulong dstAddress = dstBaseAddress + (ulong)dstOffset; + + Span<byte> pixel = data.Slice(srcOffset, 1); + + _context.PhysicalMemory.Write(dstAddress, pixel); + } + } } + + _finished = true; } } }
\ No newline at end of file diff --git a/Ryujinx.Graphics.Gpu/Engine/MethodCopyTexture.cs b/Ryujinx.Graphics.Gpu/Engine/MethodCopyTexture.cs index c482451a..1b47eac2 100644 --- a/Ryujinx.Graphics.Gpu/Engine/MethodCopyTexture.cs +++ b/Ryujinx.Graphics.Gpu/Engine/MethodCopyTexture.cs @@ -64,6 +64,29 @@ namespace Ryujinx.Graphics.Gpu.Engine srcTexture.HostTexture.CopyTo(dstTexture.HostTexture, srcRegion, dstRegion, linearFilter); + // For an out of bounds copy, we must ensure that the copy wraps to the next line, + // so for a copy from a 64x64 texture, in the region [32, 96[, there are 32 pixels that are + // outside the bounds of the texture. We fill the destination with the first 32 pixels + // of the next line on the source texture. + // This can be emulated with 2 copies (the first copy handles the region inside the bounds, + // the second handles the region outside of the bounds). + // We must also extend the source texture by one line to ensure we can wrap on the last line. + // This is required by the (guest) OpenGL driver. + if (srcRegion.X2 > srcTexture.Info.Width) + { + srcCopyTexture.Height++; + + srcTexture = _textureManager.FindOrCreateTexture(srcCopyTexture); + + srcRegion = new Extents2D( + srcRegion.X1 - srcTexture.Info.Width, + srcRegion.Y1 + 1, + srcRegion.X2 - srcTexture.Info.Width, + srcRegion.Y2 + 1); + + srcTexture.HostTexture.CopyTo(dstTexture.HostTexture, srcRegion, dstRegion, linearFilter); + } + dstTexture.Modified = true; } } diff --git a/Ryujinx.Graphics.Gpu/Engine/MethodUniformBufferUpdate.cs b/Ryujinx.Graphics.Gpu/Engine/MethodUniformBufferUpdate.cs index 43bab243..12d44f51 100644 --- a/Ryujinx.Graphics.Gpu/Engine/MethodUniformBufferUpdate.cs +++ b/Ryujinx.Graphics.Gpu/Engine/MethodUniformBufferUpdate.cs @@ -1,3 +1,4 @@ +using Ryujinx.Graphics.Gpu.Memory; using Ryujinx.Graphics.Gpu.State; namespace Ryujinx.Graphics.Gpu.Engine @@ -8,6 +9,11 @@ namespace Ryujinx.Graphics.Gpu.Engine { var uniformBuffer = state.Get<UniformBufferState>(MethodOffset.UniformBufferState); + if (_context.MemoryManager.Translate(uniformBuffer.Address.Pack() + (uint)uniformBuffer.Offset) == MemoryManager.BadAddress) + { + return; + } + _context.MemoryAccessor.Write(uniformBuffer.Address.Pack() + (uint)uniformBuffer.Offset, argument); state.SetUniformBufferOffset(uniformBuffer.Offset + 4); diff --git a/Ryujinx.Graphics.Gpu/Engine/Methods.cs b/Ryujinx.Graphics.Gpu/Engine/Methods.cs index 19e67993..18fd7e70 100644 --- a/Ryujinx.Graphics.Gpu/Engine/Methods.cs +++ b/Ryujinx.Graphics.Gpu/Engine/Methods.cs @@ -89,8 +89,8 @@ namespace Ryujinx.Graphics.Gpu.Engine UpdateRenderTargetStateIfNeeded(state); if (state.QueryModified(MethodOffset.DepthTestEnable, - MethodOffset.DepthWriteEnable, - MethodOffset.DepthTestFunc)) + MethodOffset.DepthWriteEnable, + MethodOffset.DepthTestFunc)) { UpdateDepthTestState(state); } @@ -101,16 +101,16 @@ namespace Ryujinx.Graphics.Gpu.Engine } if (state.QueryModified(MethodOffset.DepthBiasState, - MethodOffset.DepthBiasFactor, - MethodOffset.DepthBiasUnits, - MethodOffset.DepthBiasClamp)) + MethodOffset.DepthBiasFactor, + MethodOffset.DepthBiasUnits, + MethodOffset.DepthBiasClamp)) { UpdateDepthBiasState(state); } if (state.QueryModified(MethodOffset.StencilBackMasks, - MethodOffset.StencilTestState, - MethodOffset.StencilBackTestState)) + MethodOffset.StencilTestState, + MethodOffset.StencilBackTestState)) { UpdateStencilTestState(state); } @@ -143,9 +143,9 @@ namespace Ryujinx.Graphics.Gpu.Engine } if (state.QueryModified(MethodOffset.VertexBufferDrawState, - MethodOffset.VertexBufferInstanced, - MethodOffset.VertexBufferState, - MethodOffset.VertexBufferEndAddress)) + MethodOffset.VertexBufferInstanced, + MethodOffset.VertexBufferState, + MethodOffset.VertexBufferEndAddress)) { UpdateVertexBufferState(state); } @@ -160,7 +160,11 @@ namespace Ryujinx.Graphics.Gpu.Engine UpdateRtColorMask(state); } - if (state.QueryModified(MethodOffset.BlendEnable, MethodOffset.BlendState)) + if (state.QueryModified(MethodOffset.BlendIndependent, + MethodOffset.BlendStateCommon, + MethodOffset.BlendEnableCommon, + MethodOffset.BlendEnable, + MethodOffset.BlendState)) { UpdateBlendState(state); } @@ -288,6 +292,10 @@ namespace Ryujinx.Graphics.Gpu.Engine private void UpdateViewportTransform(GpuState state) { + bool flipY = (state.Get<int>(MethodOffset.YControl) & 1) != 0; + + float yFlip = flipY ? -1 : 1; + Viewport[] viewports = new Viewport[Constants.TotalViewports]; for (int index = 0; index < Constants.TotalViewports; index++) @@ -299,7 +307,7 @@ namespace Ryujinx.Graphics.Gpu.Engine float y = transform.TranslateY - MathF.Abs(transform.ScaleY); float width = transform.ScaleX * 2; - float height = transform.ScaleY * 2; + float height = transform.ScaleY * 2 * yFlip; RectangleF region = new RectangleF(x, y, width, height); @@ -390,7 +398,9 @@ namespace Ryujinx.Graphics.Gpu.Engine { var samplerPool = state.Get<PoolState>(MethodOffset.SamplerPoolState); - _textureManager.SetGraphicsSamplerPool(samplerPool.Address.Pack(), samplerPool.MaximumId); + var samplerIndex = state.Get<SamplerIndex>(MethodOffset.SamplerIndex); + + _textureManager.SetGraphicsSamplerPool(samplerPool.Address.Pack(), samplerPool.MaximumId, samplerIndex); } private void UpdateTexturePoolState(GpuState state) @@ -548,22 +558,42 @@ namespace Ryujinx.Graphics.Gpu.Engine private void UpdateBlendState(GpuState state) { + bool blendIndependent = state.Get<Boolean32>(MethodOffset.BlendIndependent); + BlendState[] blends = new BlendState[8]; for (int index = 0; index < 8; index++) { - bool enable = state.Get<Boolean32>(MethodOffset.BlendEnable, index); - - var blend = state.Get<BlendState>(MethodOffset.BlendState, index); + BlendDescriptor descriptor; - BlendDescriptor descriptor = new BlendDescriptor( - enable, - blend.ColorOp, - blend.ColorSrcFactor, - blend.ColorDstFactor, - blend.AlphaOp, - blend.AlphaSrcFactor, - blend.AlphaDstFactor); + if (blendIndependent) + { + bool enable = state.Get<Boolean32> (MethodOffset.BlendEnable, index); + var blend = state.Get<BlendState>(MethodOffset.BlendState, index); + + descriptor = new BlendDescriptor( + enable, + blend.ColorOp, + blend.ColorSrcFactor, + blend.ColorDstFactor, + blend.AlphaOp, + blend.AlphaSrcFactor, + blend.AlphaDstFactor); + } + else + { + bool enable = state.Get<Boolean32> (MethodOffset.BlendEnable, 0); + var blend = state.Get<BlendStateCommon>(MethodOffset.BlendStateCommon); + + descriptor = new BlendDescriptor( + enable, + blend.ColorOp, + blend.ColorSrcFactor, + blend.ColorDstFactor, + blend.AlphaOp, + blend.AlphaSrcFactor, + blend.AlphaDstFactor); + } _context.Renderer.Pipeline.BindBlendState(index, descriptor); } |
