mirror of
https://git.naxdy.org/Mirror/Ryujinx.git
synced 2025-01-03 22:43:07 +00:00
169 lines
5.8 KiB
C#
169 lines
5.8 KiB
C#
|
using System;
|
||
|
using System.Collections.Generic;
|
||
|
using System.Numerics;
|
||
|
|
||
|
namespace Ryujinx.Graphics.Shader.Translation
|
||
|
{
|
||
|
class AttributeUsage
|
||
|
{
|
||
|
public bool NextUsesFixedFuncAttributes { get; private set; }
|
||
|
public int UsedInputAttributes { get; private set; }
|
||
|
public int UsedOutputAttributes { get; private set; }
|
||
|
public HashSet<int> UsedInputAttributesPerPatch { get; }
|
||
|
public HashSet<int> UsedOutputAttributesPerPatch { get; }
|
||
|
public HashSet<int> NextUsedInputAttributesPerPatch { get; private set; }
|
||
|
public int PassthroughAttributes { get; private set; }
|
||
|
private int _nextUsedInputAttributes;
|
||
|
private int _thisUsedInputAttributes;
|
||
|
private Dictionary<int, int> _perPatchAttributeLocations;
|
||
|
private readonly IGpuAccessor _gpuAccessor;
|
||
|
|
||
|
public UInt128 NextInputAttributesComponents { get; private set; }
|
||
|
public UInt128 ThisInputAttributesComponents { get; private set; }
|
||
|
|
||
|
public AttributeUsage(IGpuAccessor gpuAccessor)
|
||
|
{
|
||
|
_gpuAccessor = gpuAccessor;
|
||
|
|
||
|
UsedInputAttributesPerPatch = new();
|
||
|
UsedOutputAttributesPerPatch = new();
|
||
|
}
|
||
|
|
||
|
public void SetInputUserAttribute(int index, int component)
|
||
|
{
|
||
|
int mask = 1 << index;
|
||
|
|
||
|
UsedInputAttributes |= mask;
|
||
|
_thisUsedInputAttributes |= mask;
|
||
|
ThisInputAttributesComponents |= UInt128.One << (index * 4 + component);
|
||
|
}
|
||
|
|
||
|
public void SetInputUserAttributePerPatch(int index)
|
||
|
{
|
||
|
UsedInputAttributesPerPatch.Add(index);
|
||
|
}
|
||
|
|
||
|
public void SetOutputUserAttribute(int index)
|
||
|
{
|
||
|
UsedOutputAttributes |= 1 << index;
|
||
|
}
|
||
|
|
||
|
public void SetOutputUserAttributePerPatch(int index)
|
||
|
{
|
||
|
UsedOutputAttributesPerPatch.Add(index);
|
||
|
}
|
||
|
|
||
|
public void MergeFromtNextStage(bool gpPassthrough, bool nextUsesFixedFunctionAttributes, AttributeUsage nextStage)
|
||
|
{
|
||
|
NextInputAttributesComponents = nextStage.ThisInputAttributesComponents;
|
||
|
NextUsedInputAttributesPerPatch = nextStage.UsedInputAttributesPerPatch;
|
||
|
NextUsesFixedFuncAttributes = nextUsesFixedFunctionAttributes;
|
||
|
MergeOutputUserAttributes(gpPassthrough, nextStage.UsedInputAttributes, nextStage.UsedInputAttributesPerPatch);
|
||
|
|
||
|
if (UsedOutputAttributesPerPatch.Count != 0)
|
||
|
{
|
||
|
// Regular and per-patch input/output locations can't overlap,
|
||
|
// so we must assign on our location using unused regular input/output locations.
|
||
|
|
||
|
Dictionary<int, int> locationsMap = new();
|
||
|
|
||
|
int freeMask = ~UsedOutputAttributes;
|
||
|
|
||
|
foreach (int attr in UsedOutputAttributesPerPatch)
|
||
|
{
|
||
|
int location = BitOperations.TrailingZeroCount(freeMask);
|
||
|
if (location == 32)
|
||
|
{
|
||
|
_gpuAccessor.Log($"No enough free locations for patch input/output 0x{attr:X}.");
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
locationsMap.Add(attr, location);
|
||
|
freeMask &= ~(1 << location);
|
||
|
}
|
||
|
|
||
|
// Both stages must agree on the locations, so use the same "map" for both.
|
||
|
_perPatchAttributeLocations = locationsMap;
|
||
|
nextStage._perPatchAttributeLocations = locationsMap;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void MergeOutputUserAttributes(bool gpPassthrough, int mask, IEnumerable<int> perPatch)
|
||
|
{
|
||
|
_nextUsedInputAttributes = mask;
|
||
|
|
||
|
if (gpPassthrough)
|
||
|
{
|
||
|
PassthroughAttributes = mask & ~UsedOutputAttributes;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
UsedOutputAttributes |= mask;
|
||
|
UsedOutputAttributesPerPatch.UnionWith(perPatch);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public int GetPerPatchAttributeLocation(int index)
|
||
|
{
|
||
|
if (_perPatchAttributeLocations == null || !_perPatchAttributeLocations.TryGetValue(index, out int location))
|
||
|
{
|
||
|
return index;
|
||
|
}
|
||
|
|
||
|
return location;
|
||
|
}
|
||
|
|
||
|
public bool IsUsedOutputAttribute(int attr)
|
||
|
{
|
||
|
// The check for fixed function attributes on the next stage is conservative,
|
||
|
// returning false if the output is just not used by the next stage is also valid.
|
||
|
if (NextUsesFixedFuncAttributes &&
|
||
|
attr >= AttributeConsts.UserAttributeBase &&
|
||
|
attr < AttributeConsts.UserAttributeEnd)
|
||
|
{
|
||
|
int index = (attr - AttributeConsts.UserAttributeBase) >> 4;
|
||
|
return (_nextUsedInputAttributes & (1 << index)) != 0;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
public int GetFreeUserAttribute(bool isOutput, int index)
|
||
|
{
|
||
|
int useMask = isOutput ? _nextUsedInputAttributes : _thisUsedInputAttributes;
|
||
|
int bit = -1;
|
||
|
|
||
|
while (useMask != -1)
|
||
|
{
|
||
|
bit = BitOperations.TrailingZeroCount(~useMask);
|
||
|
|
||
|
if (bit == 32)
|
||
|
{
|
||
|
bit = -1;
|
||
|
break;
|
||
|
}
|
||
|
else if (index < 1)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
useMask |= 1 << bit;
|
||
|
index--;
|
||
|
}
|
||
|
|
||
|
return bit;
|
||
|
}
|
||
|
|
||
|
public void SetAllInputUserAttributes()
|
||
|
{
|
||
|
UsedInputAttributes |= Constants.AllAttributesMask;
|
||
|
ThisInputAttributesComponents |= ~UInt128.Zero >> (128 - Constants.MaxAttributes * 4);
|
||
|
}
|
||
|
|
||
|
public void SetAllOutputUserAttributes()
|
||
|
{
|
||
|
UsedOutputAttributes |= Constants.AllAttributesMask;
|
||
|
}
|
||
|
}
|
||
|
}
|