aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.Gpu/Engine
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2019-12-05 17:34:47 -0300
committerThog <thog@protonmail.com>2020-01-09 02:13:00 +0100
commite25b7c9848b6ec486eb513297b5c536857665c7f (patch)
treec1ccb6c58bed0f7ece835359516330104feb8f4d /Ryujinx.Graphics.Gpu/Engine
parent6a98c643cabeea25dc42e19fe475a687a034a532 (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.cs2
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/ComputeParams.cs3
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/Inline2Memory.cs87
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/MethodCopyTexture.cs23
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/MethodUniformBufferUpdate.cs6
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/Methods.cs78
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);
}