0
0
Fork 0

Add XML documentation to Ryujinx.Graphics.Gpu.State

This commit is contained in:
gdkchan 2019-12-31 13:32:06 -03:00 committed by Thog
parent 430faeb8ef
commit d1c0a64e6a
47 changed files with 419 additions and 125 deletions

View file

@ -2,6 +2,9 @@ using Ryujinx.Graphics.GAL;
namespace Ryujinx.Graphics.Gpu.State namespace Ryujinx.Graphics.Gpu.State
{ {
/// <summary>
/// Color buffer blending parameters.
/// </summary>
struct BlendState struct BlendState
{ {
public Boolean32 SeparateAlpha; public Boolean32 SeparateAlpha;

View file

@ -2,6 +2,9 @@ using Ryujinx.Graphics.GAL;
namespace Ryujinx.Graphics.Gpu.State namespace Ryujinx.Graphics.Gpu.State
{ {
/// <summary>
/// Color buffer blending parameters, shared by all color buffers.
/// </summary>
struct BlendStateCommon struct BlendStateCommon
{ {
public Boolean32 SeparateAlpha; public Boolean32 SeparateAlpha;

View file

@ -1,5 +1,8 @@
namespace Ryujinx.Graphics.Gpu.State namespace Ryujinx.Graphics.Gpu.State
{ {
/// <summary>
/// Boolean value, stored as a 32-bits integer in memory.
/// </summary>
struct Boolean32 struct Boolean32
{ {
private uint _value; private uint _value;

View file

@ -1,5 +1,8 @@
namespace Ryujinx.Graphics.Gpu.State namespace Ryujinx.Graphics.Gpu.State
{ {
/// <summary>
/// Color buffer clear color.
/// </summary>
struct ClearColors struct ClearColors
{ {
public float Red; public float Red;

View file

@ -1,5 +1,8 @@
namespace Ryujinx.Graphics.Gpu.State namespace Ryujinx.Graphics.Gpu.State
{ {
/// <summary>
/// Condition for conditional rendering.
/// </summary>
enum Condition enum Condition
{ {
Never, Never,

View file

@ -1,5 +1,8 @@
namespace Ryujinx.Graphics.Gpu.State namespace Ryujinx.Graphics.Gpu.State
{ {
/// <summary>
/// Condition parameters for conditional rendering.
/// </summary>
struct ConditionState struct ConditionState
{ {
public GpuVa Address; public GpuVa Address;

View file

@ -1,5 +1,8 @@
namespace Ryujinx.Graphics.Gpu.State namespace Ryujinx.Graphics.Gpu.State
{ {
/// <summary>
/// Buffer to buffer copy parameters.
/// </summary>
struct CopyBufferParams struct CopyBufferParams
{ {
public GpuVa SrcAddress; public GpuVa SrcAddress;

View file

@ -1,19 +1,34 @@
namespace Ryujinx.Graphics.Gpu.State namespace Ryujinx.Graphics.Gpu.State
{ {
/// <summary>
/// Buffer to buffer copy vector swizzle parameters.
/// </summary>
struct CopyBufferSwizzle struct CopyBufferSwizzle
{ {
public uint Swizzle; public uint Swizzle;
/// <summary>
/// Unpacks the size of each vector component of the copy.
/// </summary>
/// <returns>Vector component size</returns>
public int UnpackComponentSize() public int UnpackComponentSize()
{ {
return (int)((Swizzle >> 16) & 3) + 1; return (int)((Swizzle >> 16) & 3) + 1;
} }
/// <summary>
/// Unpacks the number of components of the source vector of the copy.
/// </summary>
/// <returns>Number of vector components</returns>
public int UnpackSrcComponentsCount() public int UnpackSrcComponentsCount()
{ {
return (int)((Swizzle >> 20) & 7) + 1; return (int)((Swizzle >> 20) & 7) + 1;
} }
/// <summary>
/// Unpacks the number of components of the destination vector of the copy.
/// </summary>
/// <returns>Number of vector components</returns>
public int UnpackDstComponentsCount() public int UnpackDstComponentsCount()
{ {
return (int)((Swizzle >> 24) & 7) + 1; return (int)((Swizzle >> 24) & 7) + 1;

View file

@ -1,5 +1,8 @@
namespace Ryujinx.Graphics.Gpu.State namespace Ryujinx.Graphics.Gpu.State
{ {
/// <summary>
/// Buffer to texture copy parameters.
/// </summary>
struct CopyBufferTexture struct CopyBufferTexture
{ {
public MemoryLayout MemoryLayout; public MemoryLayout MemoryLayout;

View file

@ -1,5 +1,8 @@
namespace Ryujinx.Graphics.Gpu.State namespace Ryujinx.Graphics.Gpu.State
{ {
/// <summary>
/// Texture copy region.
/// </summary>
struct CopyRegion struct CopyRegion
{ {
public int DstX; public int DstX;

View file

@ -1,5 +1,8 @@
namespace Ryujinx.Graphics.Gpu.State namespace Ryujinx.Graphics.Gpu.State
{ {
/// <summary>
/// Texture to texture (with optional resizing) copy parameters.
/// </summary>
struct CopyTexture struct CopyTexture
{ {
public RtFormat Format; public RtFormat Format;

View file

@ -1,5 +1,8 @@
namespace Ryujinx.Graphics.Gpu.State namespace Ryujinx.Graphics.Gpu.State
{ {
/// <summary>
/// Texture to texture copy control.
/// </summary>
struct CopyTextureControl struct CopyTextureControl
{ {
public uint Packed; public uint Packed;

View file

@ -1,5 +1,8 @@
namespace Ryujinx.Graphics.Gpu.State namespace Ryujinx.Graphics.Gpu.State
{ {
/// <summary>
/// Depth bias (also called polygon offset) parameters.
/// </summary>
struct DepthBiasState struct DepthBiasState
{ {
public Boolean32 PointEnable; public Boolean32 PointEnable;

View file

@ -2,6 +2,9 @@ using Ryujinx.Graphics.GAL;
namespace Ryujinx.Graphics.Gpu.State namespace Ryujinx.Graphics.Gpu.State
{ {
/// <summary>
/// Face culling and orientation parameters.
/// </summary>
struct FaceState struct FaceState
{ {
public Boolean32 CullEnable; public Boolean32 CullEnable;

View file

@ -3,6 +3,9 @@ using System.Runtime.InteropServices;
namespace Ryujinx.Graphics.Gpu.State namespace Ryujinx.Graphics.Gpu.State
{ {
/// <summary>
/// GPU state.
/// </summary>
class GpuState class GpuState
{ {
private const int RegistersCount = 0xe00; private const int RegistersCount = 0xe00;
@ -11,6 +14,9 @@ namespace Ryujinx.Graphics.Gpu.State
private int[] _backingMemory; private int[] _backingMemory;
/// <summary>
/// GPU register information.
/// </summary>
private struct Register private struct Register
{ {
public MethodCallback Callback; public MethodCallback Callback;
@ -25,6 +31,9 @@ namespace Ryujinx.Graphics.Gpu.State
private Register[] _registers; private Register[] _registers;
/// <summary>
/// Creates a new instance of the GPU state.
/// </summary>
public GpuState() public GpuState()
{ {
_backingMemory = new int[RegistersCount]; _backingMemory = new int[RegistersCount];
@ -56,6 +65,10 @@ namespace Ryujinx.Graphics.Gpu.State
InitializeDefaultState(); InitializeDefaultState();
} }
/// <summary>
/// Calls a GPU method, using this state.
/// </summary>
/// <param name="meth">The GPU method to be called</param>
public void CallMethod(MethodParams meth) public void CallMethod(MethodParams meth)
{ {
Register register = _registers[meth.Method]; Register register = _registers[meth.Method];
@ -67,24 +80,31 @@ namespace Ryujinx.Graphics.Gpu.State
_backingMemory[meth.Method] = meth.Argument; _backingMemory[meth.Method] = meth.Argument;
MethodCallback callback = register.Callback; register.Callback?.Invoke(this, meth.Argument);
if (callback != null)
{
callback(this, meth.Argument);
}
} }
/// <summary>
/// Reads data from a GPU register at the given offset.
/// </summary>
/// <param name="offset">Offset to be read</param>
/// <returns>Data at the register</returns>
public int Read(int offset) public int Read(int offset)
{ {
return _backingMemory[offset]; return _backingMemory[offset];
} }
/// <summary>
/// Writes a offset value at the uniform buffer offset register.
/// </summary>
/// <param name="offset">The offset to be written</param>
public void SetUniformBufferOffset(int offset) public void SetUniformBufferOffset(int offset)
{ {
_backingMemory[(int)MethodOffset.UniformBufferState + 3] = offset; _backingMemory[(int)MethodOffset.UniformBufferState + 3] = offset;
} }
/// <summary>
/// Initializes registers with the default state.
/// </summary>
private void InitializeDefaultState() private void InitializeDefaultState()
{ {
// Depth ranges. // Depth ranges.
@ -107,6 +127,12 @@ namespace Ryujinx.Graphics.Gpu.State
} }
} }
/// <summary>
/// Registers a callback that is called every time a GPU method, or methods are called.
/// </summary>
/// <param name="offset">Offset of the method</param>
/// <param name="count">Word count of the methods region</param>
/// <param name="callback">Calllback to be called</param>
public void RegisterCallback(MethodOffset offset, int count, MethodCallback callback) public void RegisterCallback(MethodOffset offset, int count, MethodCallback callback)
{ {
for (int index = 0; index < count; index++) for (int index = 0; index < count; index++)
@ -115,11 +141,21 @@ namespace Ryujinx.Graphics.Gpu.State
} }
} }
/// <summary>
/// Registers a callback that is called every time a GPU method is called.
/// </summary>
/// <param name="offset">Offset of the method</param>
/// <param name="callback">Calllback to be called</param>
public void RegisterCallback(MethodOffset offset, MethodCallback callback) public void RegisterCallback(MethodOffset offset, MethodCallback callback)
{ {
_registers[(int)offset].Callback = callback; _registers[(int)offset].Callback = callback;
} }
/// <summary>
/// Checks if a given register has been modified since the last call to this method.
/// </summary>
/// <param name="offset">Register offset</param>
/// <returns>True if modified, false otherwise</returns>
public bool QueryModified(MethodOffset offset) public bool QueryModified(MethodOffset offset)
{ {
bool modified = _registers[(int)offset].Modified; bool modified = _registers[(int)offset].Modified;
@ -129,6 +165,12 @@ namespace Ryujinx.Graphics.Gpu.State
return modified; return modified;
} }
/// <summary>
/// Checks if two 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>
/// <returns>True if any register was modified, false otherwise</returns>
public bool QueryModified(MethodOffset m1, MethodOffset m2) public bool QueryModified(MethodOffset m1, MethodOffset m2)
{ {
bool modified = _registers[(int)m1].Modified || bool modified = _registers[(int)m1].Modified ||
@ -140,6 +182,13 @@ namespace Ryujinx.Graphics.Gpu.State
return modified; return modified;
} }
/// <summary>
/// Checks if two 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>
/// <returns>True if any register was modified, false otherwise</returns>
public bool QueryModified(MethodOffset m1, MethodOffset m2, MethodOffset m3) public bool QueryModified(MethodOffset m1, MethodOffset m2, MethodOffset m3)
{ {
bool modified = _registers[(int)m1].Modified || bool modified = _registers[(int)m1].Modified ||
@ -153,6 +202,14 @@ namespace Ryujinx.Graphics.Gpu.State
return modified; return modified;
} }
/// <summary>
/// Checks if two 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>
/// <returns>True if any register was modified, false otherwise</returns>
public bool QueryModified(MethodOffset m1, MethodOffset m2, MethodOffset m3, MethodOffset m4) public bool QueryModified(MethodOffset m1, MethodOffset m2, MethodOffset m3, MethodOffset m4)
{ {
bool modified = _registers[(int)m1].Modified || bool modified = _registers[(int)m1].Modified ||
@ -168,6 +225,15 @@ namespace Ryujinx.Graphics.Gpu.State
return modified; return modified;
} }
/// <summary>
/// Checks if two 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>
/// <returns>True if any register was modified, false otherwise</returns>
public bool QueryModified( public bool QueryModified(
MethodOffset m1, MethodOffset m1,
MethodOffset m2, MethodOffset m2,
@ -190,6 +256,13 @@ namespace Ryujinx.Graphics.Gpu.State
return modified; return modified;
} }
/// <summary>
/// Gets indexed data from 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>
/// <returns>The data at the specified location</returns>
public T Get<T>(MethodOffset offset, int index) where T : struct public T Get<T>(MethodOffset offset, int index) where T : struct
{ {
Register register = _registers[(int)offset]; Register register = _registers[(int)offset];
@ -202,6 +275,12 @@ namespace Ryujinx.Graphics.Gpu.State
return Get<T>(offset + index * register.Stride); return Get<T>(offset + index * register.Stride);
} }
/// <summary>
/// Gets data from a given register offset.
/// </summary>
/// <typeparam name="T">Type of the data</typeparam>
/// <param name="offset">Register offset</param>
/// <returns>The data at the specified location</returns>
public T Get<T>(MethodOffset offset) where T : struct public T Get<T>(MethodOffset offset) where T : struct
{ {
return MemoryMarshal.Cast<int, T>(_backingMemory.AsSpan().Slice((int)offset))[0]; return MemoryMarshal.Cast<int, T>(_backingMemory.AsSpan().Slice((int)offset))[0];

View file

@ -4,15 +4,37 @@ using System.Runtime.InteropServices;
namespace Ryujinx.Graphics.Gpu.State namespace Ryujinx.Graphics.Gpu.State
{ {
/// <summary>
/// GPU State item sizes table.
/// </summary>
static class GpuStateTable static class GpuStateTable
{ {
/// <summary>
/// GPU state table item, with size for structures, and count for indexed state data.
/// </summary>
public struct TableItem public struct TableItem
{ {
/// <summary>
/// Offset of the data.
/// </summary>
public MethodOffset Offset { get; } public MethodOffset Offset { get; }
public int Size { get; } /// <summary>
/// Size in words.
/// </summary>
public int Size { get; }
/// <summary>
/// Count for indexed data, or 1 if not indexed.
/// </summary>
public int Count { get; } public int Count { get; }
/// <summary>
/// Constructs the table item structure.
/// </summary>
/// <param name="offset">Data offset</param>
/// <param name="type">Data type</param>
/// <param name="count">Data count, for indexed data</param>
public TableItem(MethodOffset offset, Type type, int count) public TableItem(MethodOffset offset, Type type, int count)
{ {
int sizeInBytes = Marshal.SizeOf(type); int sizeInBytes = Marshal.SizeOf(type);
@ -25,6 +47,9 @@ namespace Ryujinx.Graphics.Gpu.State
} }
} }
/// <summary>
/// Table of GPU state structure sizes and counts.
/// </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), 8),

View file

@ -1,10 +1,17 @@
namespace Ryujinx.Graphics.Gpu.State namespace Ryujinx.Graphics.Gpu.State
{ {
/// <summary>
/// Split GPU virtual address.
/// </summary>
struct GpuVa struct GpuVa
{ {
public uint High; public uint High;
public uint Low; public uint Low;
/// <summary>
/// Packs the split address into a 64-bits address value.
/// </summary>
/// <returns></returns>
public ulong Pack() public ulong Pack()
{ {
return Low | ((ulong)High << 32); return Low | ((ulong)High << 32);

View file

@ -2,6 +2,10 @@ using Ryujinx.Graphics.GAL;
namespace Ryujinx.Graphics.Gpu.State namespace Ryujinx.Graphics.Gpu.State
{ {
/// <summary>
/// GPU index buffer state.
/// This is used on indexed draws.
/// </summary>
struct IndexBufferState struct IndexBufferState
{ {
public GpuVa Address; public GpuVa Address;

View file

@ -1,5 +1,8 @@
namespace Ryujinx.Graphics.Gpu.State namespace Ryujinx.Graphics.Gpu.State
{ {
/// <summary>
/// Inline-to-memory copy parameters.
/// </summary>
struct Inline2MemoryParams struct Inline2MemoryParams
{ {
public int LineLengthIn; public int LineLengthIn;

View file

@ -1,5 +1,8 @@
namespace Ryujinx.Graphics.Gpu.State namespace Ryujinx.Graphics.Gpu.State
{ {
/// <summary>
/// Memory layout parameters, for block linear textures.
/// </summary>
struct MemoryLayout struct MemoryLayout
{ {
public uint Packed; public uint Packed;

View file

@ -1,5 +1,8 @@
namespace Ryujinx.Graphics.Gpu.State namespace Ryujinx.Graphics.Gpu.State
{ {
/// <summary>
/// GPU method offset.
/// </summary>
enum MethodOffset enum MethodOffset
{ {
I2mParams = 0x60, I2mParams = 0x60,

View file

@ -1,5 +1,8 @@
namespace Ryujinx.Graphics.Gpu.State namespace Ryujinx.Graphics.Gpu.State
{ {
/// <summary>
/// Texture or sampler pool state.
/// </summary>
struct PoolState struct PoolState
{ {
public GpuVa Address; public GpuVa Address;

View file

@ -1,5 +1,8 @@
namespace Ryujinx.Graphics.Gpu.State namespace Ryujinx.Graphics.Gpu.State
{ {
/// <summary>
/// Primitive restart state.
/// </summary>
struct PrimitiveRestartState struct PrimitiveRestartState
{ {
public Boolean32 Enable; public Boolean32 Enable;

View file

@ -2,6 +2,9 @@ using Ryujinx.Graphics.GAL;
namespace Ryujinx.Graphics.Gpu.State namespace Ryujinx.Graphics.Gpu.State
{ {
/// <summary>
/// Draw primitive type.
/// </summary>
enum PrimitiveType enum PrimitiveType
{ {
Points, Points,
@ -23,28 +26,32 @@ namespace Ryujinx.Graphics.Gpu.State
static class PrimitiveTypeConverter static class PrimitiveTypeConverter
{ {
public static PrimitiveTopology Convert(this PrimitiveType topology) /// <summary>
/// Converts the primitive type into something that can be used with the host API.
/// </summary>
/// <param name="type">The primitive type to convert</param>
/// <returns>A host compatible enum value</returns>
public static PrimitiveTopology Convert(this PrimitiveType type)
{ {
switch (topology) return type switch
{ {
case PrimitiveType.Points: return PrimitiveTopology.Points; PrimitiveType.Points => PrimitiveTopology.Points,
case PrimitiveType.Lines: return PrimitiveTopology.Lines; PrimitiveType.Lines => PrimitiveTopology.Lines,
case PrimitiveType.LineLoop: return PrimitiveTopology.LineLoop; PrimitiveType.LineLoop => PrimitiveTopology.LineLoop,
case PrimitiveType.LineStrip: return PrimitiveTopology.LineStrip; PrimitiveType.LineStrip => PrimitiveTopology.LineStrip,
case PrimitiveType.Triangles: return PrimitiveTopology.Triangles; PrimitiveType.Triangles => PrimitiveTopology.Triangles,
case PrimitiveType.TriangleStrip: return PrimitiveTopology.TriangleStrip; PrimitiveType.TriangleStrip => PrimitiveTopology.TriangleStrip,
case PrimitiveType.TriangleFan: return PrimitiveTopology.TriangleFan; PrimitiveType.TriangleFan => PrimitiveTopology.TriangleFan,
case PrimitiveType.Quads: return PrimitiveTopology.Quads; PrimitiveType.Quads => PrimitiveTopology.Quads,
case PrimitiveType.QuadStrip: return PrimitiveTopology.QuadStrip; PrimitiveType.QuadStrip => PrimitiveTopology.QuadStrip,
case PrimitiveType.Polygon: return PrimitiveTopology.Polygon; PrimitiveType.Polygon => PrimitiveTopology.Polygon,
case PrimitiveType.LinesAdjacency: return PrimitiveTopology.LinesAdjacency; PrimitiveType.LinesAdjacency => PrimitiveTopology.LinesAdjacency,
case PrimitiveType.LineStripAdjacency: return PrimitiveTopology.LineStripAdjacency; PrimitiveType.LineStripAdjacency => PrimitiveTopology.LineStripAdjacency,
case PrimitiveType.TrianglesAdjacency: return PrimitiveTopology.TrianglesAdjacency; PrimitiveType.TrianglesAdjacency => PrimitiveTopology.TrianglesAdjacency,
case PrimitiveType.TriangleStripAdjacency: return PrimitiveTopology.TriangleStripAdjacency; PrimitiveType.TriangleStripAdjacency => PrimitiveTopology.TriangleStripAdjacency,
case PrimitiveType.Patches: return PrimitiveTopology.Patches; PrimitiveType.Patches => PrimitiveTopology.Patches,
} _ => PrimitiveTopology.Triangles
};
return PrimitiveTopology.Triangles;
} }
} }
} }

View file

@ -1,5 +1,8 @@
namespace Ryujinx.Graphics.Gpu.State namespace Ryujinx.Graphics.Gpu.State
{ {
/// <summary>
/// Counter type for GPU counter reporting.
/// </summary>
enum ReportCounterType enum ReportCounterType
{ {
Zero = 0, Zero = 0,

View file

@ -1,5 +1,8 @@
namespace Ryujinx.Graphics.Gpu.State namespace Ryujinx.Graphics.Gpu.State
{ {
/// <summary>
/// GPU counter report mode.
/// </summary>
enum ReportMode enum ReportMode
{ {
Semaphore = 0, Semaphore = 0,

View file

@ -1,5 +1,8 @@
namespace Ryujinx.Graphics.Gpu.State namespace Ryujinx.Graphics.Gpu.State
{ {
/// <summary>
/// GPU counter report state.
/// </summary>
struct ReportState struct ReportState
{ {
public GpuVa Address; public GpuVa Address;

View file

@ -1,5 +1,8 @@
namespace Ryujinx.Graphics.Gpu.State namespace Ryujinx.Graphics.Gpu.State
{ {
/// <summary>
/// Counter type for GPU counter reset.
/// </summary>
enum ResetCounterType enum ResetCounterType
{ {
SamplesPassed = 1, SamplesPassed = 1,

View file

@ -1,24 +1,44 @@
namespace Ryujinx.Graphics.Gpu.State namespace Ryujinx.Graphics.Gpu.State
{ {
/// <summary>
/// Render target color buffer mask.
/// This defines which color channels are written to the color buffer.
/// </summary>
struct RtColorMask struct RtColorMask
{ {
public uint Packed; public uint Packed;
/// <summary>
/// Unpacks red channel enable.
/// </summary>
/// <returns>True to write the new red channel color, false to keep the old value</returns>
public bool UnpackRed() public bool UnpackRed()
{ {
return (Packed & 0x1) != 0; return (Packed & 0x1) != 0;
} }
/// <summary>
/// Unpacks green channel enable.
/// </summary>
/// <returns>True to write the new green channel color, false to keep the old value</returns>
public bool UnpackGreen() public bool UnpackGreen()
{ {
return (Packed & 0x10) != 0; return (Packed & 0x10) != 0;
} }
/// <summary>
/// Unpacks blue channel enable.
/// </summary>
/// <returns>True to write the new blue channel color, false to keep the old value</returns>
public bool UnpackBlue() public bool UnpackBlue()
{ {
return (Packed & 0x100) != 0; return (Packed & 0x100) != 0;
} }
/// <summary>
/// Unpacks alpha channel enable.
/// </summary>
/// <returns>True to write the new alpha channel color, false to keep the old value</returns>
public bool UnpackAlpha() public bool UnpackAlpha()
{ {
return (Packed & 0x1000) != 0; return (Packed & 0x1000) != 0;

View file

@ -1,5 +1,8 @@
namespace Ryujinx.Graphics.Gpu.State namespace Ryujinx.Graphics.Gpu.State
{ {
/// <summary>
/// Render target color buffer state.
/// </summary>
struct RtColorState struct RtColorState
{ {
public GpuVa Address; public GpuVa Address;

View file

@ -1,14 +1,26 @@
namespace Ryujinx.Graphics.Gpu.State namespace Ryujinx.Graphics.Gpu.State
{ {
/// <summary>
/// Render target draw buffers control.
/// </summary>
struct RtControl struct RtControl
{ {
public uint Packed; public uint Packed;
/// <summary>
/// Unpacks the number of active draw buffers.
/// </summary>
/// <returns>Number of active draw buffers</returns>
public int UnpackCount() public int UnpackCount()
{ {
return (int)(Packed & 0xf); return (int)(Packed & 0xf);
} }
/// <summary>
/// Unpacks the color attachment index for a given draw buffer.
/// </summary>
/// <param name="index">Index of the draw buffer</param>
/// <returns>Attachment index</returns>
public int UnpackPermutationIndex(int index) public int UnpackPermutationIndex(int index)
{ {
return (int)((Packed >> (4 + index * 3)) & 7); return (int)((Packed >> (4 + index * 3)) & 7);

View file

@ -1,5 +1,8 @@
namespace Ryujinx.Graphics.Gpu.State namespace Ryujinx.Graphics.Gpu.State
{ {
/// <summary>
/// Render target depth-stencil buffer state.
/// </summary>
struct RtDepthStencilState struct RtDepthStencilState
{ {
public GpuVa Address; public GpuVa Address;

View file

@ -3,6 +3,9 @@ using Ryujinx.Graphics.Gpu.Image;
namespace Ryujinx.Graphics.Gpu.State namespace Ryujinx.Graphics.Gpu.State
{ {
/// <summary>
/// Render target buffer texture format.
/// </summary>
enum RtFormat enum RtFormat
{ {
D32Float = 0xa, D32Float = 0xa,
@ -69,73 +72,77 @@ namespace Ryujinx.Graphics.Gpu.State
static class RtFormatConverter static class RtFormatConverter
{ {
/// <summary>
/// Converts the render target buffer texture format to a host compatible format.
/// </summary>
/// <param name="format">Render target format</param>
/// <returns>Host compatible format enum value</returns>
public static FormatInfo Convert(this RtFormat format) public static FormatInfo Convert(this RtFormat format)
{ {
switch (format) return format switch
{ {
case RtFormat.D32Float: return new FormatInfo(Format.D32Float, 1, 1, 4); RtFormat.D32Float => new FormatInfo(Format.D32Float, 1, 1, 4),
case RtFormat.D16Unorm: return new FormatInfo(Format.D16Unorm, 1, 1, 2); RtFormat.D16Unorm => new FormatInfo(Format.D16Unorm, 1, 1, 2),
case RtFormat.D24UnormS8Uint: return new FormatInfo(Format.D24UnormS8Uint, 1, 1, 4); RtFormat.D24UnormS8Uint => new FormatInfo(Format.D24UnormS8Uint, 1, 1, 4),
case RtFormat.D24Unorm: return new FormatInfo(Format.D24UnormS8Uint, 1, 1, 4); RtFormat.D24Unorm => new FormatInfo(Format.D24UnormS8Uint, 1, 1, 4),
case RtFormat.S8UintD24Unorm: return new FormatInfo(Format.D24UnormS8Uint, 1, 1, 4); RtFormat.S8UintD24Unorm => new FormatInfo(Format.D24UnormS8Uint, 1, 1, 4),
case RtFormat.S8Uint: return new FormatInfo(Format.S8Uint, 1, 1, 1); RtFormat.S8Uint => new FormatInfo(Format.S8Uint, 1, 1, 1),
case RtFormat.D32FloatS8Uint: return new FormatInfo(Format.D32FloatS8Uint, 1, 1, 8); RtFormat.D32FloatS8Uint => new FormatInfo(Format.D32FloatS8Uint, 1, 1, 8),
case RtFormat.R32G32B32A32Float: return new FormatInfo(Format.R32G32B32A32Float, 1, 1, 16); RtFormat.R32G32B32A32Float => new FormatInfo(Format.R32G32B32A32Float, 1, 1, 16),
case RtFormat.R32G32B32A32Sint: return new FormatInfo(Format.R32G32B32A32Sint, 1, 1, 16); RtFormat.R32G32B32A32Sint => new FormatInfo(Format.R32G32B32A32Sint, 1, 1, 16),
case RtFormat.R32G32B32A32Uint: return new FormatInfo(Format.R32G32B32A32Uint, 1, 1, 16); RtFormat.R32G32B32A32Uint => new FormatInfo(Format.R32G32B32A32Uint, 1, 1, 16),
case RtFormat.R32G32B32X32Float: return new FormatInfo(Format.R32G32B32A32Float, 1, 1, 16); RtFormat.R32G32B32X32Float => new FormatInfo(Format.R32G32B32A32Float, 1, 1, 16),
case RtFormat.R32G32B32X32Sint: return new FormatInfo(Format.R32G32B32A32Sint, 1, 1, 16); RtFormat.R32G32B32X32Sint => new FormatInfo(Format.R32G32B32A32Sint, 1, 1, 16),
case RtFormat.R32G32B32X32Uint: return new FormatInfo(Format.R32G32B32A32Uint, 1, 1, 16); RtFormat.R32G32B32X32Uint => new FormatInfo(Format.R32G32B32A32Uint, 1, 1, 16),
case RtFormat.R16G16B16X16Unorm: return new FormatInfo(Format.R16G16B16A16Unorm, 1, 1, 8); RtFormat.R16G16B16X16Unorm => new FormatInfo(Format.R16G16B16A16Unorm, 1, 1, 8),
case RtFormat.R16G16B16X16Snorm: return new FormatInfo(Format.R16G16B16A16Snorm, 1, 1, 8); RtFormat.R16G16B16X16Snorm => new FormatInfo(Format.R16G16B16A16Snorm, 1, 1, 8),
case RtFormat.R16G16B16X16Sint: return new FormatInfo(Format.R16G16B16A16Sint, 1, 1, 8); RtFormat.R16G16B16X16Sint => new FormatInfo(Format.R16G16B16A16Sint, 1, 1, 8),
case RtFormat.R16G16B16X16Uint: return new FormatInfo(Format.R16G16B16A16Uint, 1, 1, 8); RtFormat.R16G16B16X16Uint => new FormatInfo(Format.R16G16B16A16Uint, 1, 1, 8),
case RtFormat.R16G16B16A16Float: return new FormatInfo(Format.R16G16B16A16Float, 1, 1, 8); RtFormat.R16G16B16A16Float => new FormatInfo(Format.R16G16B16A16Float, 1, 1, 8),
case RtFormat.R32G32Float: return new FormatInfo(Format.R32G32Float, 1, 1, 8); RtFormat.R32G32Float => new FormatInfo(Format.R32G32Float, 1, 1, 8),
case RtFormat.R32G32Sint: return new FormatInfo(Format.R32G32Sint, 1, 1, 8); RtFormat.R32G32Sint => new FormatInfo(Format.R32G32Sint, 1, 1, 8),
case RtFormat.R32G32Uint: return new FormatInfo(Format.R32G32Uint, 1, 1, 8); RtFormat.R32G32Uint => new FormatInfo(Format.R32G32Uint, 1, 1, 8),
case RtFormat.R16G16B16X16Float: return new FormatInfo(Format.R16G16B16A16Float, 1, 1, 8); RtFormat.R16G16B16X16Float => new FormatInfo(Format.R16G16B16A16Float, 1, 1, 8),
case RtFormat.B8G8R8A8Unorm: return new FormatInfo(Format.B8G8R8A8Unorm, 1, 1, 4); RtFormat.B8G8R8A8Unorm => new FormatInfo(Format.B8G8R8A8Unorm, 1, 1, 4),
case RtFormat.B8G8R8A8Srgb: return new FormatInfo(Format.B8G8R8A8Srgb, 1, 1, 4); RtFormat.B8G8R8A8Srgb => new FormatInfo(Format.B8G8R8A8Srgb, 1, 1, 4),
case RtFormat.R10G10B10A2Unorm: return new FormatInfo(Format.R10G10B10A2Unorm, 1, 1, 4); RtFormat.R10G10B10A2Unorm => new FormatInfo(Format.R10G10B10A2Unorm, 1, 1, 4),
case RtFormat.R10G10B10A2Uint: return new FormatInfo(Format.R10G10B10A2Uint, 1, 1, 4); RtFormat.R10G10B10A2Uint => new FormatInfo(Format.R10G10B10A2Uint, 1, 1, 4),
case RtFormat.R8G8B8A8Unorm: return new FormatInfo(Format.R8G8B8A8Unorm, 1, 1, 4); RtFormat.R8G8B8A8Unorm => new FormatInfo(Format.R8G8B8A8Unorm, 1, 1, 4),
case RtFormat.R8G8B8A8Srgb: return new FormatInfo(Format.R8G8B8A8Srgb, 1, 1, 4); RtFormat.R8G8B8A8Srgb => new FormatInfo(Format.R8G8B8A8Srgb, 1, 1, 4),
case RtFormat.R8G8B8X8Snorm: return new FormatInfo(Format.R8G8B8A8Snorm, 1, 1, 4); RtFormat.R8G8B8X8Snorm => new FormatInfo(Format.R8G8B8A8Snorm, 1, 1, 4),
case RtFormat.R8G8B8X8Sint: return new FormatInfo(Format.R8G8B8A8Sint, 1, 1, 4); RtFormat.R8G8B8X8Sint => new FormatInfo(Format.R8G8B8A8Sint, 1, 1, 4),
case RtFormat.R8G8B8X8Uint: return new FormatInfo(Format.R8G8B8A8Uint, 1, 1, 4); RtFormat.R8G8B8X8Uint => new FormatInfo(Format.R8G8B8A8Uint, 1, 1, 4),
case RtFormat.R16G16Unorm: return new FormatInfo(Format.R16G16Unorm, 1, 1, 4); RtFormat.R16G16Unorm => new FormatInfo(Format.R16G16Unorm, 1, 1, 4),
case RtFormat.R16G16Snorm: return new FormatInfo(Format.R16G16Snorm, 1, 1, 4); RtFormat.R16G16Snorm => new FormatInfo(Format.R16G16Snorm, 1, 1, 4),
case RtFormat.R16G16Sint: return new FormatInfo(Format.R16G16Sint, 1, 1, 4); RtFormat.R16G16Sint => new FormatInfo(Format.R16G16Sint, 1, 1, 4),
case RtFormat.R16G16Uint: return new FormatInfo(Format.R16G16Uint, 1, 1, 4); RtFormat.R16G16Uint => new FormatInfo(Format.R16G16Uint, 1, 1, 4),
case RtFormat.R16G16Float: return new FormatInfo(Format.R16G16Float, 1, 1, 4); RtFormat.R16G16Float => new FormatInfo(Format.R16G16Float, 1, 1, 4),
case RtFormat.R11G11B10Float: return new FormatInfo(Format.R11G11B10Float, 1, 1, 4); RtFormat.R11G11B10Float => new FormatInfo(Format.R11G11B10Float, 1, 1, 4),
case RtFormat.R32Sint: return new FormatInfo(Format.R32Sint, 1, 1, 4); RtFormat.R32Sint => new FormatInfo(Format.R32Sint, 1, 1, 4),
case RtFormat.R32Uint: return new FormatInfo(Format.R32Uint, 1, 1, 4); RtFormat.R32Uint => new FormatInfo(Format.R32Uint, 1, 1, 4),
case RtFormat.R32Float: return new FormatInfo(Format.R32Float, 1, 1, 4); RtFormat.R32Float => new FormatInfo(Format.R32Float, 1, 1, 4),
case RtFormat.B8G8R8X8Unorm: return new FormatInfo(Format.B8G8R8A8Unorm, 1, 1, 4); RtFormat.B8G8R8X8Unorm => new FormatInfo(Format.B8G8R8A8Unorm, 1, 1, 4),
case RtFormat.B8G8R8X8Srgb: return new FormatInfo(Format.B8G8R8A8Srgb, 1, 1, 4); RtFormat.B8G8R8X8Srgb => new FormatInfo(Format.B8G8R8A8Srgb, 1, 1, 4),
case RtFormat.B5G6R5Unorm: return new FormatInfo(Format.B5G6R5Unorm, 1, 1, 2); RtFormat.B5G6R5Unorm => new FormatInfo(Format.B5G6R5Unorm, 1, 1, 2),
case RtFormat.B5G5R5A1Unorm: return new FormatInfo(Format.B5G5R5A1Unorm, 1, 1, 2); RtFormat.B5G5R5A1Unorm => new FormatInfo(Format.B5G5R5A1Unorm, 1, 1, 2),
case RtFormat.R8G8Unorm: return new FormatInfo(Format.R8G8Unorm, 1, 1, 2); RtFormat.R8G8Unorm => new FormatInfo(Format.R8G8Unorm, 1, 1, 2),
case RtFormat.R8G8Snorm: return new FormatInfo(Format.R8G8Snorm, 1, 1, 2); RtFormat.R8G8Snorm => new FormatInfo(Format.R8G8Snorm, 1, 1, 2),
case RtFormat.R8G8Sint: return new FormatInfo(Format.R8G8Sint, 1, 1, 2); RtFormat.R8G8Sint => new FormatInfo(Format.R8G8Sint, 1, 1, 2),
case RtFormat.R8G8Uint: return new FormatInfo(Format.R8G8Uint, 1, 1, 2); RtFormat.R8G8Uint => new FormatInfo(Format.R8G8Uint, 1, 1, 2),
case RtFormat.R16Unorm: return new FormatInfo(Format.R16Unorm, 1, 1, 2); RtFormat.R16Unorm => new FormatInfo(Format.R16Unorm, 1, 1, 2),
case RtFormat.R16Snorm: return new FormatInfo(Format.R16Snorm, 1, 1, 2); RtFormat.R16Snorm => new FormatInfo(Format.R16Snorm, 1, 1, 2),
case RtFormat.R16Sint: return new FormatInfo(Format.R16Sint, 1, 1, 2); RtFormat.R16Sint => new FormatInfo(Format.R16Sint, 1, 1, 2),
case RtFormat.R16Uint: return new FormatInfo(Format.R16Uint, 1, 1, 2); RtFormat.R16Uint => new FormatInfo(Format.R16Uint, 1, 1, 2),
case RtFormat.R16Float: return new FormatInfo(Format.R16Float, 1, 1, 2); RtFormat.R16Float => new FormatInfo(Format.R16Float, 1, 1, 2),
case RtFormat.R8Unorm: return new FormatInfo(Format.R8Unorm, 1, 1, 1); RtFormat.R8Unorm => new FormatInfo(Format.R8Unorm, 1, 1, 1),
case RtFormat.R8Snorm: return new FormatInfo(Format.R8Snorm, 1, 1, 1); RtFormat.R8Snorm => new FormatInfo(Format.R8Snorm, 1, 1, 1),
case RtFormat.R8Sint: return new FormatInfo(Format.R8Sint, 1, 1, 1); RtFormat.R8Sint => new FormatInfo(Format.R8Sint, 1, 1, 1),
case RtFormat.R8Uint: return new FormatInfo(Format.R8Uint, 1, 1, 1); RtFormat.R8Uint => new FormatInfo(Format.R8Uint, 1, 1, 1),
case RtFormat.B5G5R5X1Unorm: return new FormatInfo(Format.B5G5R5X1Unorm, 1, 1, 2); RtFormat.B5G5R5X1Unorm => new FormatInfo(Format.B5G5R5X1Unorm, 1, 1, 2),
case RtFormat.R8G8B8X8Unorm: return new FormatInfo(Format.R8G8B8A8Unorm, 1, 1, 4); RtFormat.R8G8B8X8Unorm => new FormatInfo(Format.R8G8B8A8Unorm, 1, 1, 4),
case RtFormat.R8G8B8X8Srgb: return new FormatInfo(Format.R8G8B8A8Srgb, 1, 1, 4); RtFormat.R8G8B8X8Srgb => new FormatInfo(Format.R8G8B8A8Srgb, 1, 1, 4),
} _ => FormatInfo.Default
};
return FormatInfo.Default;
} }
} }
} }

View file

@ -1,5 +1,8 @@
namespace Ryujinx.Graphics.Gpu.State namespace Ryujinx.Graphics.Gpu.State
{ {
/// <summary>
/// Sampler pool indexing mode.
/// </summary>
enum SamplerIndex enum SamplerIndex
{ {
Independently = 0, Independently = 0,

View file

@ -1,5 +1,8 @@
namespace Ryujinx.Graphics.Gpu.State namespace Ryujinx.Graphics.Gpu.State
{ {
/// <summary>
/// Graphics shader stage state.
/// </summary>
struct ShaderState struct ShaderState
{ {
public uint Control; public uint Control;
@ -19,6 +22,11 @@ namespace Ryujinx.Graphics.Gpu.State
public uint Unknown0x38; public uint Unknown0x38;
public uint Unknown0x3c; public uint Unknown0x3c;
/// <summary>
/// Unpacks shader enable information.
/// Must be ignored for vertex shaders, those are always enabled.
/// </summary>
/// <returns>True if the stage is enabled, false otherwise</returns>
public bool UnpackEnable() public bool UnpackEnable()
{ {
return (Control & 1) != 0; return (Control & 1) != 0;

View file

@ -1,5 +1,8 @@
namespace Ryujinx.Graphics.Gpu.State namespace Ryujinx.Graphics.Gpu.State
{ {
/// <summary>
/// Shader stage name.
/// </summary>
enum ShaderType enum ShaderType
{ {
Vertex, Vertex,

View file

@ -1,5 +1,8 @@
namespace Ryujinx.Graphics.Gpu.State namespace Ryujinx.Graphics.Gpu.State
{ {
/// <summary>
/// 3D, 2D or 1D texture size.
/// </summary>
struct Size3D struct Size3D
{ {
public int Width; public int Width;

View file

@ -1,34 +0,0 @@
namespace Ryujinx.Graphics.Gpu.State
{
enum StateWriteFlags
{
InputAssemblerGroup =
VertexAttribState |
PrimitiveRestartState |
IndexBufferState |
VertexBufferState,
RenderTargetGroup =
RtColorState |
RtDepthStencilState,
RtColorState = 1 << 0,
ViewportTransform = 1 << 1,
DepthBiasState = 1 << 2,
RtDepthStencilState = 1 << 3,
DepthTestState = 1 << 4,
VertexAttribState = 1 << 5,
StencilTestState = 1 << 6,
SamplerPoolState = 1 << 7,
TexturePoolState = 1 << 8,
PrimitiveRestartState = 1 << 9,
IndexBufferState = 1 << 10,
FaceState = 1 << 11,
RtColorMask = 1 << 12,
VertexBufferState = 1 << 13,
BlendState = 1 << 14,
ShaderState = 1 << 15,
Any = -1
}
}

View file

@ -1,5 +1,8 @@
namespace Ryujinx.Graphics.Gpu.State namespace Ryujinx.Graphics.Gpu.State
{ {
/// <summary>
/// Stencil test masks for back tests.
/// </summary>
struct StencilBackMasks struct StencilBackMasks
{ {
public int FuncRef; public int FuncRef;

View file

@ -2,6 +2,9 @@ using Ryujinx.Graphics.GAL;
namespace Ryujinx.Graphics.Gpu.State namespace Ryujinx.Graphics.Gpu.State
{ {
/// <summary>
/// Stencil back test state.
/// </summary>
struct StencilBackTestState struct StencilBackTestState
{ {
public Boolean32 TwoSided; public Boolean32 TwoSided;

View file

@ -2,6 +2,9 @@ using Ryujinx.Graphics.GAL;
namespace Ryujinx.Graphics.Gpu.State namespace Ryujinx.Graphics.Gpu.State
{ {
/// <summary>
/// Stencil front test state and masks.
/// </summary>
struct StencilTestState struct StencilTestState
{ {
public Boolean32 Enable; public Boolean32 Enable;

View file

@ -1,5 +1,8 @@
namespace Ryujinx.Graphics.Gpu.State namespace Ryujinx.Graphics.Gpu.State
{ {
/// <summary>
/// Uniform buffer state for the uniform buffer currently being modified.
/// </summary>
struct UniformBufferState struct UniformBufferState
{ {
public int Size; public int Size;

View file

@ -1,19 +1,34 @@
namespace Ryujinx.Graphics.Gpu.State namespace Ryujinx.Graphics.Gpu.State
{ {
/// <summary>
/// Vertex buffer attribute state.
/// </summary>
struct VertexAttribState struct VertexAttribState
{ {
public uint Attribute; public uint Attribute;
/// <summary>
/// Unpacks the index of the vertex buffer this attribute belongs to.
/// </summary>
/// <returns>Vertex buffer index</returns>
public int UnpackBufferIndex() public int UnpackBufferIndex()
{ {
return (int)(Attribute & 0x1f); return (int)(Attribute & 0x1f);
} }
/// <summary>
/// Unpacks the offset, in bytes, of the attribute on the vertex buffer.
/// </summary>
/// <returns>Attribute offset in bytes</returns>
public int UnpackOffset() public int UnpackOffset()
{ {
return (int)((Attribute >> 7) & 0x3fff); return (int)((Attribute >> 7) & 0x3fff);
} }
/// <summary>
/// Unpacks the Maxwell attribute format integer.
/// </summary>
/// <returns>Attribute format integer</returns>
public uint UnpackFormat() public uint UnpackFormat()
{ {
return Attribute & 0x3fe00000; return Attribute & 0x3fe00000;

View file

@ -1,5 +1,8 @@
namespace Ryujinx.Graphics.Gpu.State namespace Ryujinx.Graphics.Gpu.State
{ {
/// <summary>
/// Draw state for non-indexed draws.
/// </summary>
struct VertexBufferDrawState struct VertexBufferDrawState
{ {
public int First; public int First;

View file

@ -1,16 +1,27 @@
namespace Ryujinx.Graphics.Gpu.State namespace Ryujinx.Graphics.Gpu.State
{ {
/// <summary>
/// Vertex buffer state.
/// </summary>
struct VertexBufferState struct VertexBufferState
{ {
public uint Control; public uint Control;
public GpuVa Address; public GpuVa Address;
public int Divisor; public int Divisor;
/// <summary>
/// Vertex buffer stride, defined as the number of bytes occupied by each vertex in memory.
/// </summary>
/// <returns>Vertex buffer stride</returns>
public int UnpackStride() public int UnpackStride()
{ {
return (int)(Control & 0xfff); return (int)(Control & 0xfff);
} }
/// <summary>
/// Vertex buffer enable.
/// </summary>
/// <returns>True if the vertex buffer is enabled, false otherwise</returns>
public bool UnpackEnable() public bool UnpackEnable()
{ {
return (Control & (1 << 12)) != 0; return (Control & (1 << 12)) != 0;

View file

@ -1,5 +1,8 @@
namespace Ryujinx.Graphics.Gpu.State namespace Ryujinx.Graphics.Gpu.State
{ {
/// <summary>
/// Viewport extents for viewport clipping, also includes depth range.
/// </summary>
struct ViewportExtents struct ViewportExtents
{ {
public ushort X; public ushort X;

View file

@ -2,6 +2,9 @@ using Ryujinx.Graphics.GAL;
namespace Ryujinx.Graphics.Gpu.State namespace Ryujinx.Graphics.Gpu.State
{ {
/// <summary>
/// Viewport transform parameters, for viewport transformation.
/// </summary>
struct ViewportTransform struct ViewportTransform
{ {
public float ScaleX; public float ScaleX;
@ -13,21 +16,37 @@ namespace Ryujinx.Graphics.Gpu.State
public uint Swizzle; public uint Swizzle;
public uint SubpixelPrecisionBias; public uint SubpixelPrecisionBias;
/// <summary>
/// Unpacks viewport swizzle of the position X component.
/// </summary>
/// <returns>Swizzle enum value</returns>
public ViewportSwizzle UnpackSwizzleX() public ViewportSwizzle UnpackSwizzleX()
{ {
return (ViewportSwizzle)(Swizzle & 7); return (ViewportSwizzle)(Swizzle & 7);
} }
/// <summary>
/// Unpacks viewport swizzle of the position Y component.
/// </summary>
/// <returns>Swizzle enum value</returns>
public ViewportSwizzle UnpackSwizzleY() public ViewportSwizzle UnpackSwizzleY()
{ {
return (ViewportSwizzle)((Swizzle >> 4) & 7); return (ViewportSwizzle)((Swizzle >> 4) & 7);
} }
/// <summary>
/// Unpacks viewport swizzle of the position Z component.
/// </summary>
/// <returns>Swizzle enum value</returns>
public ViewportSwizzle UnpackSwizzleZ() public ViewportSwizzle UnpackSwizzleZ()
{ {
return (ViewportSwizzle)((Swizzle >> 8) & 7); return (ViewportSwizzle)((Swizzle >> 8) & 7);
} }
/// <summary>
/// Unpacks viewport swizzle of the position W component.
/// </summary>
/// <returns>Swizzle enum value</returns>
public ViewportSwizzle UnpackSwizzleW() public ViewportSwizzle UnpackSwizzleW()
{ {
return (ViewportSwizzle)((Swizzle >> 12) & 7); return (ViewportSwizzle)((Swizzle >> 12) & 7);