Initial support for the guest OpenGL driver (NVIDIA and Nouveau)
This commit is contained in:
parent
6a98c643ca
commit
e25b7c9848
25 changed files with 581 additions and 102 deletions
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
BlendDescriptor descriptor;
|
||||
|
||||
var blend = state.Get<BlendState>(MethodOffset.BlendState, index);
|
||||
if (blendIndependent)
|
||||
{
|
||||
bool enable = state.Get<Boolean32> (MethodOffset.BlendEnable, index);
|
||||
var blend = state.Get<BlendState>(MethodOffset.BlendState, index);
|
||||
|
||||
BlendDescriptor descriptor = new BlendDescriptor(
|
||||
enable,
|
||||
blend.ColorOp,
|
||||
blend.ColorSrcFactor,
|
||||
blend.ColorDstFactor,
|
||||
blend.AlphaOp,
|
||||
blend.AlphaSrcFactor,
|
||||
blend.AlphaDstFactor);
|
||||
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);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue