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:
parent
75ec30c962
commit
a728610b40
10 changed files with 140 additions and 16 deletions
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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),
|
||||||
};
|
};
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue