Implement Constant Color blends (#1119)

* Implement Constant Color blends and init blend states

* Address gdkchan's comments

Also adds Set methods to GpuState

* Fix descriptions of QueryModified
This commit is contained in:
mageven 2020-04-25 18:30:43 +05:30 committed by GitHub
parent 75ec30c962
commit a728610b40
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 140 additions and 16 deletions

View file

@ -4,6 +4,7 @@ namespace Ryujinx.Graphics.GAL
{ {
public bool Enable { get; } public bool Enable { get; }
public ColorF BlendConstant { get; }
public BlendOp ColorOp { get; } public BlendOp ColorOp { get; }
public BlendFactor ColorSrcFactor { get; } public BlendFactor ColorSrcFactor { get; }
public BlendFactor ColorDstFactor { get; } public BlendFactor ColorDstFactor { get; }
@ -13,6 +14,7 @@ namespace Ryujinx.Graphics.GAL
public BlendDescriptor( public BlendDescriptor(
bool enable, bool enable,
ColorF blendConstant,
BlendOp colorOp, BlendOp colorOp,
BlendFactor colorSrcFactor, BlendFactor colorSrcFactor,
BlendFactor colorDstFactor, BlendFactor colorDstFactor,
@ -21,6 +23,7 @@ namespace Ryujinx.Graphics.GAL
BlendFactor alphaDstFactor) BlendFactor alphaDstFactor)
{ {
Enable = enable; Enable = enable;
BlendConstant = blendConstant;
ColorOp = colorOp; ColorOp = colorOp;
ColorSrcFactor = colorSrcFactor; ColorSrcFactor = colorSrcFactor;
ColorDstFactor = colorDstFactor; ColorDstFactor = colorDstFactor;

View file

@ -1,6 +1,8 @@
using System;
namespace Ryujinx.Graphics.GAL namespace Ryujinx.Graphics.GAL
{ {
public struct ColorF public struct ColorF : IEquatable<ColorF>
{ {
public float Red { get; } public float Red { get; }
public float Green { get; } public float Green { get; }
@ -14,5 +16,17 @@ namespace Ryujinx.Graphics.GAL
Blue = blue; Blue = blue;
Alpha = alpha; Alpha = alpha;
} }
public bool Equals(ColorF color) => Red == color.Red &&
Green == color.Green &&
Blue == color.Blue &&
Alpha == color.Alpha;
public override bool Equals(object obj) => (obj is ColorF color) && Equals(color);
public override int GetHashCode() => HashCode.Combine(Red, Green, Blue, Alpha);
public static bool operator ==(ColorF l, ColorF r) => l.Equals(r);
public static bool operator !=(ColorF l, ColorF r) => !l.Equals(r);
} }
} }

View file

@ -26,8 +26,6 @@ namespace Ryujinx.Graphics.GAL
void SetBlendState(int index, BlendDescriptor blend); void SetBlendState(int index, BlendDescriptor blend);
void SetBlendColor(ColorF color);
void SetDepthBias(PolygonModeMask enables, float factor, float units, float clamp); void SetDepthBias(PolygonModeMask enables, float factor, float units, float clamp);
void SetDepthClamp(bool clampNear, bool clampFar); void SetDepthClamp(bool clampNear, bool clampFar);
void SetDepthMode(DepthMode mode); void SetDepthMode(DepthMode mode);

View file

@ -229,6 +229,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
} }
if (state.QueryModified(MethodOffset.BlendIndependent, if (state.QueryModified(MethodOffset.BlendIndependent,
MethodOffset.BlendConstant,
MethodOffset.BlendStateCommon, MethodOffset.BlendStateCommon,
MethodOffset.BlendEnableCommon, MethodOffset.BlendEnableCommon,
MethodOffset.BlendEnable, MethodOffset.BlendEnable,
@ -749,8 +750,9 @@ namespace Ryujinx.Graphics.Gpu.Engine
private void UpdateBlendState(GpuState state) private void UpdateBlendState(GpuState state)
{ {
bool blendIndependent = state.Get<Boolean32>(MethodOffset.BlendIndependent); bool blendIndependent = state.Get<Boolean32>(MethodOffset.BlendIndependent);
ColorF blendConstant = state.Get<ColorF>(MethodOffset.BlendConstant);
for (int index = 0; index < 8; index++) for (int index = 0; index < Constants.TotalRenderTargets; index++)
{ {
BlendDescriptor descriptor; BlendDescriptor descriptor;
@ -761,6 +763,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
descriptor = new BlendDescriptor( descriptor = new BlendDescriptor(
enable, enable,
blendConstant,
blend.ColorOp, blend.ColorOp,
blend.ColorSrcFactor, blend.ColorSrcFactor,
blend.ColorDstFactor, blend.ColorDstFactor,
@ -775,6 +778,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
descriptor = new BlendDescriptor( descriptor = new BlendDescriptor(
enable, enable,
blendConstant,
blend.ColorOp, blend.ColorOp,
blend.ColorSrcFactor, blend.ColorSrcFactor,
blend.ColorDstFactor, blend.ColorDstFactor,

View file

@ -17,5 +17,15 @@ namespace Ryujinx.Graphics.Gpu.State
public BlendFactor AlphaDstFactor; public BlendFactor AlphaDstFactor;
public uint Padding; public uint Padding;
#pragma warning restore CS0649 #pragma warning restore CS0649
public static BlendState Default = new BlendState
{
ColorOp = BlendOp.Add,
ColorSrcFactor = BlendFactor.One,
ColorDstFactor = BlendFactor.Zero,
AlphaOp = BlendOp.Add,
AlphaSrcFactor = BlendFactor.One,
AlphaDstFactor = BlendFactor.Zero
};
} }
} }

View file

@ -17,5 +17,15 @@ namespace Ryujinx.Graphics.Gpu.State
public uint Unknown0x1354; public uint Unknown0x1354;
public BlendFactor AlphaDstFactor; public BlendFactor AlphaDstFactor;
#pragma warning restore CS0649 #pragma warning restore CS0649
public static BlendStateCommon Default = new BlendStateCommon
{
ColorOp = BlendOp.Add,
ColorSrcFactor = BlendFactor.One,
ColorDstFactor = BlendFactor.Zero,
AlphaOp = BlendOp.Add,
AlphaSrcFactor = BlendFactor.One,
AlphaDstFactor = BlendFactor.Zero
};
} }
} }

View file

@ -141,6 +141,14 @@ namespace Ryujinx.Graphics.Gpu.State
{ {
_backingMemory[(int)MethodOffset.RtColorMask + index] = 0x1111; _backingMemory[(int)MethodOffset.RtColorMask + index] = 0x1111;
} }
// Default blend states
Set(MethodOffset.BlendStateCommon, BlendStateCommon.Default);
for (int index = 0; index < Constants.TotalRenderTargets; index++)
{
Set(MethodOffset.BlendState, index, BlendState.Default);
}
} }
/// <summary> /// <summary>
@ -199,7 +207,7 @@ namespace Ryujinx.Graphics.Gpu.State
} }
/// <summary> /// <summary>
/// Checks if two registers have been modified since the last call to this method. /// Checks if three registers have been modified since the last call to this method.
/// </summary> /// </summary>
/// <param name="m1">First register offset</param> /// <param name="m1">First register offset</param>
/// <param name="m2">Second register offset</param> /// <param name="m2">Second register offset</param>
@ -219,7 +227,7 @@ namespace Ryujinx.Graphics.Gpu.State
} }
/// <summary> /// <summary>
/// Checks if two registers have been modified since the last call to this method. /// Checks if four registers have been modified since the last call to this method.
/// </summary> /// </summary>
/// <param name="m1">First register offset</param> /// <param name="m1">First register offset</param>
/// <param name="m2">Second register offset</param> /// <param name="m2">Second register offset</param>
@ -242,7 +250,7 @@ namespace Ryujinx.Graphics.Gpu.State
} }
/// <summary> /// <summary>
/// Checks if two registers have been modified since the last call to this method. /// Checks if five registers have been modified since the last call to this method.
/// </summary> /// </summary>
/// <param name="m1">First register offset</param> /// <param name="m1">First register offset</param>
/// <param name="m2">Second register offset</param> /// <param name="m2">Second register offset</param>
@ -272,6 +280,41 @@ namespace Ryujinx.Graphics.Gpu.State
return modified; return modified;
} }
/// <summary>
/// Checks if six registers have been modified since the last call to this method.
/// </summary>
/// <param name="m1">First register offset</param>
/// <param name="m2">Second register offset</param>
/// <param name="m3">Third register offset</param>
/// <param name="m4">Fourth register offset</param>
/// <param name="m5">Fifth register offset</param>
/// <param name="m6">Sixth register offset</param>
/// <returns>True if any register was modified, false otherwise</returns>
public bool QueryModified(
MethodOffset m1,
MethodOffset m2,
MethodOffset m3,
MethodOffset m4,
MethodOffset m5,
MethodOffset m6)
{
bool modified = _registers[(int)m1].Modified ||
_registers[(int)m2].Modified ||
_registers[(int)m3].Modified ||
_registers[(int)m4].Modified ||
_registers[(int)m5].Modified ||
_registers[(int)m6].Modified;
_registers[(int)m1].Modified = false;
_registers[(int)m2].Modified = false;
_registers[(int)m3].Modified = false;
_registers[(int)m4].Modified = false;
_registers[(int)m5].Modified = false;
_registers[(int)m6].Modified = false;
return modified;
}
/// <summary> /// <summary>
/// Gets indexed data from a given register offset. /// Gets indexed data from a given register offset.
/// </summary> /// </summary>
@ -301,5 +344,36 @@ namespace Ryujinx.Graphics.Gpu.State
{ {
return MemoryMarshal.Cast<int, T>(_backingMemory.AsSpan().Slice((int)offset))[0]; return MemoryMarshal.Cast<int, T>(_backingMemory.AsSpan().Slice((int)offset))[0];
} }
/// <summary>
/// Sets indexed data to a given register offset.
/// </summary>
/// <typeparam name="T">Type of the data</typeparam>
/// <param name="offset">Register offset</param>
/// <param name="index">Index for indexed data</param>
/// <param name="data">The data to set</param>
public void Set<T>(MethodOffset offset, int index, T data) where T : struct
{
Register register = _registers[(int)offset];
if ((uint)index >= register.Count)
{
throw new ArgumentOutOfRangeException(nameof(index));
}
Set(offset + index * register.Stride, data);
}
/// <summary>
/// Sets data to a given register offset.
/// </summary>
/// <typeparam name="T">Type of the data</typeparam>
/// <param name="offset">Register offset</param>
/// <param name="data">The data to set</param>
public void Set<T>(MethodOffset offset, T data) where T : struct
{
ReadOnlySpan<int> intSpan = MemoryMarshal.Cast<T, int>(MemoryMarshal.CreateReadOnlySpan(ref data, 1));
intSpan.CopyTo(_backingMemory.AsSpan().Slice((int)offset, intSpan.Length));
}
} }
} }

View file

@ -1,3 +1,4 @@
using Ryujinx.Graphics.GAL;
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
@ -52,7 +53,7 @@ namespace Ryujinx.Graphics.Gpu.State
/// </summary> /// </summary>
public static TableItem[] Table = new TableItem[] public static TableItem[] Table = new TableItem[]
{ {
new TableItem(MethodOffset.RtColorState, typeof(RtColorState), 8), new TableItem(MethodOffset.RtColorState, typeof(RtColorState), Constants.TotalRenderTargets),
new TableItem(MethodOffset.ViewportTransform, typeof(ViewportTransform), Constants.TotalViewports), new TableItem(MethodOffset.ViewportTransform, typeof(ViewportTransform), Constants.TotalViewports),
new TableItem(MethodOffset.ViewportExtents, typeof(ViewportExtents), Constants.TotalViewports), new TableItem(MethodOffset.ViewportExtents, typeof(ViewportExtents), Constants.TotalViewports),
new TableItem(MethodOffset.VertexBufferDrawState, typeof(VertexBufferDrawState), 1), new TableItem(MethodOffset.VertexBufferDrawState, typeof(VertexBufferDrawState), 1),
@ -62,7 +63,7 @@ namespace Ryujinx.Graphics.Gpu.State
new TableItem(MethodOffset.RtDepthStencilState, typeof(RtDepthStencilState), 1), new TableItem(MethodOffset.RtDepthStencilState, typeof(RtDepthStencilState), 1),
new TableItem(MethodOffset.VertexAttribState, typeof(VertexAttribState), 16), new TableItem(MethodOffset.VertexAttribState, typeof(VertexAttribState), 16),
new TableItem(MethodOffset.RtDepthStencilSize, typeof(Size3D), 1), new TableItem(MethodOffset.RtDepthStencilSize, typeof(Size3D), 1),
new TableItem(MethodOffset.BlendEnable, typeof(Boolean32), 8), new TableItem(MethodOffset.BlendEnable, typeof(Boolean32), Constants.TotalRenderTargets),
new TableItem(MethodOffset.StencilTestState, typeof(StencilTestState), 1), new TableItem(MethodOffset.StencilTestState, typeof(StencilTestState), 1),
new TableItem(MethodOffset.SamplerPoolState, typeof(PoolState), 1), new TableItem(MethodOffset.SamplerPoolState, typeof(PoolState), 1),
new TableItem(MethodOffset.TexturePoolState, typeof(PoolState), 1), new TableItem(MethodOffset.TexturePoolState, typeof(PoolState), 1),
@ -72,9 +73,10 @@ namespace Ryujinx.Graphics.Gpu.State
new TableItem(MethodOffset.IndexBufferState, typeof(IndexBufferState), 1), new TableItem(MethodOffset.IndexBufferState, typeof(IndexBufferState), 1),
new TableItem(MethodOffset.VertexBufferInstanced, typeof(Boolean32), 16), new TableItem(MethodOffset.VertexBufferInstanced, typeof(Boolean32), 16),
new TableItem(MethodOffset.FaceState, typeof(FaceState), 1), new TableItem(MethodOffset.FaceState, typeof(FaceState), 1),
new TableItem(MethodOffset.RtColorMask, typeof(RtColorMask), 8), new TableItem(MethodOffset.RtColorMask, typeof(RtColorMask), Constants.TotalRenderTargets),
new TableItem(MethodOffset.VertexBufferState, typeof(VertexBufferState), 16), new TableItem(MethodOffset.VertexBufferState, typeof(VertexBufferState), 16),
new TableItem(MethodOffset.BlendState, typeof(BlendState), 8), new TableItem(MethodOffset.BlendConstant, typeof(ColorF), 1),
new TableItem(MethodOffset.BlendState, typeof(BlendState), Constants.TotalRenderTargets),
new TableItem(MethodOffset.VertexBufferEndAddress, typeof(GpuVa), 16), new TableItem(MethodOffset.VertexBufferEndAddress, typeof(GpuVa), 16),
new TableItem(MethodOffset.ShaderState, typeof(ShaderState), 6), new TableItem(MethodOffset.ShaderState, typeof(ShaderState), 6),
}; };

View file

@ -58,6 +58,7 @@ namespace Ryujinx.Graphics.Gpu.State
BlendIndependent = 0x4b9, BlendIndependent = 0x4b9,
DepthWriteEnable = 0x4ba, DepthWriteEnable = 0x4ba,
DepthTestFunc = 0x4c3, DepthTestFunc = 0x4c3,
BlendConstant = 0x4c7,
BlendStateCommon = 0x4cf, BlendStateCommon = 0x4cf,
BlendEnableCommon = 0x4d7, BlendEnableCommon = 0x4d7,
BlendEnable = 0x4d8, BlendEnable = 0x4d8,

View file

@ -35,6 +35,8 @@ namespace Ryujinx.Graphics.OpenGL
private bool _scissor0Enable = false; private bool _scissor0Enable = false;
ColorF _blendConstant = new ColorF(0, 0, 0, 0);
internal Pipeline() internal Pipeline()
{ {
_rasterizerDiscard = false; _rasterizerDiscard = false;
@ -478,11 +480,6 @@ namespace Ryujinx.Graphics.OpenGL
} }
} }
public void SetBlendColor(ColorF color)
{
GL.BlendColor(color.Red, color.Green, color.Blue, color.Alpha);
}
public void SetBlendState(int index, BlendDescriptor blend) public void SetBlendState(int index, BlendDescriptor blend)
{ {
if (!blend.Enable) if (!blend.Enable)
@ -504,6 +501,17 @@ namespace Ryujinx.Graphics.OpenGL
(BlendingFactorSrc)blend.AlphaSrcFactor.Convert(), (BlendingFactorSrc)blend.AlphaSrcFactor.Convert(),
(BlendingFactorDest)blend.AlphaDstFactor.Convert()); (BlendingFactorDest)blend.AlphaDstFactor.Convert());
if (_blendConstant != blend.BlendConstant)
{
_blendConstant = blend.BlendConstant;
GL.BlendColor(
blend.BlendConstant.Red,
blend.BlendConstant.Green,
blend.BlendConstant.Blue,
blend.BlendConstant.Alpha);
}
GL.Enable(IndexedEnableCap.Blend, index); GL.Enable(IndexedEnableCap.Blend, index);
} }