Address PR feedback
This commit is contained in:
parent
40ef18d759
commit
92703af555
39 changed files with 285 additions and 228 deletions
|
@ -5,20 +5,17 @@ namespace Ryujinx.Graphics.GAL
|
||||||
public bool SupportsAstcCompression { get; }
|
public bool SupportsAstcCompression { get; }
|
||||||
public bool SupportsNonConstantTextureOffset { get; }
|
public bool SupportsNonConstantTextureOffset { get; }
|
||||||
|
|
||||||
public int MaximumViewportDimensions { get; }
|
|
||||||
public int MaximumComputeSharedMemorySize { get; }
|
public int MaximumComputeSharedMemorySize { get; }
|
||||||
public int StorageBufferOffsetAlignment { get; }
|
public int StorageBufferOffsetAlignment { get; }
|
||||||
|
|
||||||
public Capabilities(
|
public Capabilities(
|
||||||
bool supportsAstcCompression,
|
bool supportsAstcCompression,
|
||||||
bool supportsNonConstantTextureOffset,
|
bool supportsNonConstantTextureOffset,
|
||||||
int maximumViewportDimensions,
|
|
||||||
int maximumComputeSharedMemorySize,
|
int maximumComputeSharedMemorySize,
|
||||||
int storageBufferOffsetAlignment)
|
int storageBufferOffsetAlignment)
|
||||||
{
|
{
|
||||||
SupportsAstcCompression = supportsAstcCompression;
|
SupportsAstcCompression = supportsAstcCompression;
|
||||||
SupportsNonConstantTextureOffset = supportsNonConstantTextureOffset;
|
SupportsNonConstantTextureOffset = supportsNonConstantTextureOffset;
|
||||||
MaximumViewportDimensions = maximumViewportDimensions;
|
|
||||||
MaximumComputeSharedMemorySize = maximumComputeSharedMemorySize;
|
MaximumComputeSharedMemorySize = maximumComputeSharedMemorySize;
|
||||||
StorageBufferOffsetAlignment = storageBufferOffsetAlignment;
|
StorageBufferOffsetAlignment = storageBufferOffsetAlignment;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
public const int TotalCpUniformBuffers = 8;
|
public const int TotalCpUniformBuffers = 8;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Maximum number of compute storage buffers (this is a API limitation).
|
/// Maximum number of compute storage buffers (this is an API limitation).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const int TotalCpStorageBuffers = 16;
|
public const int TotalCpStorageBuffers = 16;
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
public const int TotalGpUniformBuffers = 18;
|
public const int TotalGpUniformBuffers = 18;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Maximum number of graphics storage buffers (this is a API limitation).
|
/// Maximum number of graphics storage buffers (this is an API limitation).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const int TotalGpStorageBuffers = 16;
|
public const int TotalGpStorageBuffers = 16;
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Number of shader stages.
|
/// Number of shader stages.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const int TotalShaderStages = 5;
|
public const int ShaderStages = 5;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Maximum number of vertex buffers.
|
/// Maximum number of vertex buffers.
|
||||||
|
|
|
@ -86,7 +86,7 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Processes a single command on the FIFO.
|
/// Processes a single command on the FIFO.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns>True if the FIFO still has commands to be processed, false otherwise</returns>
|
||||||
private bool Step()
|
private bool Step()
|
||||||
{
|
{
|
||||||
if (_dmaGet != _dmaPut)
|
if (_dmaGet != _dmaPut)
|
||||||
|
|
|
@ -8,6 +8,9 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
||||||
{
|
{
|
||||||
partial class Methods
|
partial class Methods
|
||||||
{
|
{
|
||||||
|
private const int NsToTicksFractionNumerator = 384;
|
||||||
|
private const int NsToTicksFractionDenominator = 625;
|
||||||
|
|
||||||
private ulong _runningCounter;
|
private ulong _runningCounter;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -103,8 +106,10 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Converts a nanoseconds timestamp value to Maxwell time ticks.
|
/// Converts a nanoseconds timestamp value to Maxwell time ticks.
|
||||||
/// The frequency is approximately 1.63Hz.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The frequency is 614400000 Hz.
|
||||||
|
/// </remarks>
|
||||||
/// <param name="nanoseconds">Timestamp in nanoseconds</param>
|
/// <param name="nanoseconds">Timestamp in nanoseconds</param>
|
||||||
/// <returns>Maxwell ticks</returns>
|
/// <returns>Maxwell ticks</returns>
|
||||||
private static ulong ConvertNanosecondsToTicks(ulong nanoseconds)
|
private static ulong ConvertNanosecondsToTicks(ulong nanoseconds)
|
||||||
|
@ -112,13 +117,13 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
||||||
// We need to divide first to avoid overflows.
|
// We need to divide first to avoid overflows.
|
||||||
// We fix up the result later by calculating the difference and adding
|
// We fix up the result later by calculating the difference and adding
|
||||||
// that to the result.
|
// that to the result.
|
||||||
ulong divided = nanoseconds / 625;
|
ulong divided = nanoseconds / NsToTicksFractionDenominator;
|
||||||
|
|
||||||
ulong rounded = divided * 625;
|
ulong rounded = divided * NsToTicksFractionDenominator;
|
||||||
|
|
||||||
ulong errorBias = ((nanoseconds - rounded) * 384) / 625;
|
ulong errorBias = (nanoseconds - rounded) * NsToTicksFractionNumerator / NsToTicksFractionDenominator;
|
||||||
|
|
||||||
return divided * 384 + errorBias;
|
return divided * NsToTicksFractionNumerator + errorBias;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -48,7 +48,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
||||||
|
|
||||||
ShaderCache = new ShaderCache(_context);
|
ShaderCache = new ShaderCache(_context);
|
||||||
|
|
||||||
_currentProgramInfo = new ShaderProgramInfo[Constants.TotalShaderStages];
|
_currentProgramInfo = new ShaderProgramInfo[Constants.ShaderStages];
|
||||||
|
|
||||||
BufferManager = new BufferManager(context);
|
BufferManager = new BufferManager(context);
|
||||||
TextureManager = new TextureManager(context);
|
TextureManager = new TextureManager(context);
|
||||||
|
@ -201,7 +201,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Ensures that the bindings are visible to the host GPU.
|
/// Ensures that the bindings are visible to the host GPU.
|
||||||
/// This actually performs the binding using the host graphics API.
|
/// Note: this actually performs the binding using the host graphics API.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void CommitBindings()
|
private void CommitBindings()
|
||||||
{
|
{
|
||||||
|
@ -622,7 +622,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Updates host render target color masks, based on guest GPU state.
|
/// Updates host render target color masks, based on guest GPU state.
|
||||||
/// This defines with color channels are written to each color buffer.
|
/// This defines which color channels are written to each color buffer.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="state">Current GPU state</param>
|
/// <param name="state">Current GPU state</param>
|
||||||
private void UpdateRtColorMask(GpuState state)
|
private void UpdateRtColorMask(GpuState state)
|
||||||
|
@ -739,7 +739,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
||||||
|
|
||||||
_vsUsesInstanceId = gs.Shaders[0].Program.Info.UsesInstanceId;
|
_vsUsesInstanceId = gs.Shaders[0].Program.Info.UsesInstanceId;
|
||||||
|
|
||||||
for (int stage = 0; stage < Constants.TotalShaderStages; stage++)
|
for (int stage = 0; stage < Constants.ShaderStages; stage++)
|
||||||
{
|
{
|
||||||
ShaderProgramInfo info = gs.Shaders[stage].Program?.Info;
|
ShaderProgramInfo info = gs.Shaders[stage].Program?.Info;
|
||||||
|
|
||||||
|
@ -845,7 +845,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
||||||
return Target.CubemapArray;
|
return Target.CubemapArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Warning.
|
Logger.PrintWarning(LogClass.Gpu, $"Invalid sampler type \"{type}\".");
|
||||||
|
|
||||||
return Target.Texture2D;
|
return Target.Texture2D;
|
||||||
}
|
}
|
||||||
|
@ -855,8 +855,8 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
||||||
/// This waits until previous texture writes from the GPU to finish, before
|
/// This waits until previous texture writes from the GPU to finish, before
|
||||||
/// performing new operations with said textures.
|
/// performing new operations with said textures.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="state">Current GPU state</param>
|
/// <param name="state">Current GPU state (unused)</param>
|
||||||
/// <param name="argument">Method call argument</param>
|
/// <param name="argument">Method call argument (unused)</param>
|
||||||
private void TextureBarrier(GpuState state, int argument)
|
private void TextureBarrier(GpuState state, int argument)
|
||||||
{
|
{
|
||||||
_context.Renderer.Pipeline.TextureBarrier();
|
_context.Renderer.Pipeline.TextureBarrier();
|
||||||
|
@ -865,8 +865,8 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Invalidates all modified textures on the cache.
|
/// Invalidates all modified textures on the cache.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="state">Current GPU state</param>
|
/// <param name="state">Current GPU state (unused)</param>
|
||||||
/// <param name="argument">Method call argument</param>
|
/// <param name="argument">Method call argument (unused)</param>
|
||||||
private void InvalidateTextures(GpuState state, int argument)
|
private void InvalidateTextures(GpuState state, int argument)
|
||||||
{
|
{
|
||||||
TextureManager.Flush();
|
TextureManager.Flush();
|
||||||
|
@ -880,8 +880,8 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
||||||
/// and current access has the same access patterns.
|
/// and current access has the same access patterns.
|
||||||
/// This may be faster than the regular barrier on tile-based rasterizers.
|
/// This may be faster than the regular barrier on tile-based rasterizers.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="state"></param>
|
/// <param name="state">Current GPU state (unused)</param>
|
||||||
/// <param name="argument"></param>
|
/// <param name="argument">Method call argument (unused)</param>
|
||||||
private void TextureBarrierTiled(GpuState state, int argument)
|
private void TextureBarrierTiled(GpuState state, int argument)
|
||||||
{
|
{
|
||||||
_context.Renderer.Pipeline.TextureBarrierTiled();
|
_context.Renderer.Pipeline.TextureBarrierTiled();
|
||||||
|
|
|
@ -24,9 +24,11 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds a new texture to the cache, even if the texture added is already on the cache.
|
/// Adds a new texture to the cache, even if the texture added is already on the cache.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
/// Using this method is only recommended if you know that the texture is not yet on the cache,
|
/// Using this method is only recommended if you know that the texture is not yet on the cache,
|
||||||
/// otherwise it would store the same texture more than once.
|
/// otherwise it would store the same texture more than once.
|
||||||
/// </summary>
|
/// </remarks>
|
||||||
/// <param name="texture">The texture to be added to the cache</param>
|
/// <param name="texture">The texture to be added to the cache</param>
|
||||||
public void Add(Texture texture)
|
public void Add(Texture texture)
|
||||||
{
|
{
|
||||||
|
@ -48,9 +50,12 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds a new texture to the cache, or just moves it to the top of the list if the
|
/// Adds a new texture to the cache, or just moves it to the top of the list if the
|
||||||
/// texture is already on the cache. Moving the texture to the top of the list prevents
|
/// texture is already on the cache.
|
||||||
/// it from being deleted, as the textures on the bottom of the list are deleted when new ones are added.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Moving the texture to the top of the list prevents it from being deleted,
|
||||||
|
/// as the textures on the bottom of the list are deleted when new ones are added.
|
||||||
|
/// </remarks>
|
||||||
/// <param name="texture">The texture to be added, or moved to the top</param>
|
/// <param name="texture">The texture to be added, or moved to the top</param>
|
||||||
public void Lift(Texture texture)
|
public void Lift(Texture texture)
|
||||||
{
|
{
|
||||||
|
|
|
@ -18,13 +18,19 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
public Format Format { get; }
|
public Format Format { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The block width for compressed formats. Must be 1 for non-compressed formats.
|
/// The block width for compressed formats.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Must be 1 for non-compressed formats.
|
||||||
|
/// </remarks>
|
||||||
public int BlockWidth { get; }
|
public int BlockWidth { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The block height for compressed formats. Must be 1 for non-compressed formats.
|
/// The block height for compressed formats.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Must be 1 for non-compressed formats.
|
||||||
|
/// </remarks>
|
||||||
public int BlockHeight { get; }
|
public int BlockHeight { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -17,8 +17,10 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The maximum ID value of resources on the pool (inclusive).
|
/// The maximum ID value of resources on the pool (inclusive).
|
||||||
/// The maximum amount of resources on the pool is equal to this value plus one.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The maximum amount of resources on the pool is equal to this value plus one.
|
||||||
|
/// </remarks>
|
||||||
public int MaximumId { get; }
|
public int MaximumId { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -2,8 +2,10 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a filter used with texture minification linear filtering.
|
/// Represents a filter used with texture minification linear filtering.
|
||||||
/// This feature is only supported on NVIDIA GPUs.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This feature is only supported on NVIDIA GPUs.
|
||||||
|
/// </remarks>
|
||||||
enum ReductionFilter
|
enum ReductionFilter
|
||||||
{
|
{
|
||||||
Average,
|
Average,
|
||||||
|
|
|
@ -190,9 +190,11 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Changes the texture size.
|
/// Changes the texture size.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
/// This operation may also change the size of all mipmap levels, including from the parent
|
/// This operation may also change the size of all mipmap levels, including from the parent
|
||||||
/// and other possible child textures, to ensure that all sizes are consistent.
|
/// and other possible child textures, to ensure that all sizes are consistent.
|
||||||
/// </summary>
|
/// </remarks>
|
||||||
/// <param name="width">The new texture width</param>
|
/// <param name="width">The new texture width</param>
|
||||||
/// <param name="height">The new texture height</param>
|
/// <param name="height">The new texture height</param>
|
||||||
/// <param name="depthOrLayers">The new texture depth (for 3D textures) or layers (for layered textures)</param>
|
/// <param name="depthOrLayers">The new texture depth (for 3D textures) or layers (for layered textures)</param>
|
||||||
|
|
|
@ -21,8 +21,10 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Indicates if the texture is a bindless texture.
|
/// Indicates if the texture is a bindless texture.
|
||||||
/// For those textures, Handle is ignored.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// For those textures, Handle is ignored.
|
||||||
|
/// </remarks>
|
||||||
public bool IsBindless { get; }
|
public bool IsBindless { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -52,7 +52,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
_texturePoolCache = texturePoolCache;
|
_texturePoolCache = texturePoolCache;
|
||||||
_isCompute = isCompute;
|
_isCompute = isCompute;
|
||||||
|
|
||||||
int stages = isCompute ? 1 : Constants.TotalShaderStages;
|
int stages = isCompute ? 1 : Constants.ShaderStages;
|
||||||
|
|
||||||
_textureBindings = new TextureBindingInfo[stages][];
|
_textureBindings = new TextureBindingInfo[stages][];
|
||||||
_imageBindings = new TextureBindingInfo[stages][];
|
_imageBindings = new TextureBindingInfo[stages][];
|
||||||
|
@ -135,7 +135,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Ensures that the bindings are visible to the host GPU.
|
/// Ensures that the bindings are visible to the host GPU.
|
||||||
/// This actually performs the binding using the host graphics API.
|
/// Note: this actually performs the binding using the host graphics API.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void CommitBindings()
|
public void CommitBindings()
|
||||||
{
|
{
|
||||||
|
@ -164,7 +164,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Ensures that the texture bindings are visible to the host GPU.
|
/// Ensures that the texture bindings are visible to the host GPU.
|
||||||
/// This actually performs the binding using the host graphics API.
|
/// Note: this actually performs the binding using the host graphics API.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="pool">The current texture pool</param>
|
/// <param name="pool">The current texture pool</param>
|
||||||
/// <param name="stage">The shader stage using the textures to be bound</param>
|
/// <param name="stage">The shader stage using the textures to be bound</param>
|
||||||
|
@ -242,7 +242,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Ensures that the image bindings are visible to the host GPU.
|
/// Ensures that the image bindings are visible to the host GPU.
|
||||||
/// This actually performs the binding using the host graphics API.
|
/// Note: this actually performs the binding using the host graphics API.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="pool">The current texture pool</param>
|
/// <param name="pool">The current texture pool</param>
|
||||||
/// <param name="stage">The shader stage using the textures to be bound</param>
|
/// <param name="stage">The shader stage using the textures to be bound</param>
|
||||||
|
|
|
@ -753,9 +753,11 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Removes a texture from the cache.
|
/// Removes a texture from the cache.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
/// This only removes the texture from the internal list, not from the auto-deletion cache.
|
/// This only removes the texture from the internal list, not from the auto-deletion cache.
|
||||||
/// It may still have live references after the removal.
|
/// It may still have live references after the removal.
|
||||||
/// </summary>
|
/// </remarks>
|
||||||
/// <param name="texture">The texture to be removed</param>
|
/// <param name="texture">The texture to be removed</param>
|
||||||
public void RemoveTextureFromCache(Texture texture)
|
public void RemoveTextureFromCache(Texture texture)
|
||||||
{
|
{
|
||||||
|
|
|
@ -388,7 +388,7 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Extracts a 32-bits signed integer constant from the current operation code.
|
/// Extracts a 32-bits signed integer constant from the current operation code.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns>The 32-bits immediate value encoded at the current operation code</returns>
|
||||||
private int GetImm()
|
private int GetImm()
|
||||||
{
|
{
|
||||||
// Note: The immediate is signed, the sign-extension is intended here.
|
// Note: The immediate is signed, the sign-extension is intended here.
|
||||||
|
|
|
@ -53,9 +53,11 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a sub-range from the buffer.
|
/// Gets a sub-range from the buffer.
|
||||||
/// This can be used to bind and use sub-ranges of the buffer on the host API.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="address">Start address of the sub-range, must be greater or equal to the buffer address</param>
|
/// <remarks>
|
||||||
|
/// This can be used to bind and use sub-ranges of the buffer on the host API.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="address">Start address of the sub-range, must be greater than or equal to the buffer address</param>
|
||||||
/// <param name="size">Size in bytes of the sub-range, must be less than or equal to the buffer size</param>
|
/// <param name="size">Size in bytes of the sub-range, must be less than or equal to the buffer size</param>
|
||||||
/// <returns>The buffer sub-range</returns>
|
/// <returns>The buffer sub-range</returns>
|
||||||
public BufferRange GetRange(ulong address, ulong size)
|
public BufferRange GetRange(ulong address, ulong size)
|
||||||
|
@ -78,9 +80,11 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Performs guest to host memory synchronization of the buffer data.
|
/// Performs guest to host memory synchronization of the buffer data.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
/// This causes the buffer data to be overwritten if a write was detected from the CPU,
|
/// This causes the buffer data to be overwritten if a write was detected from the CPU,
|
||||||
/// since the last call to this method.
|
/// since the last call to this method.
|
||||||
/// </summary>
|
/// </remarks>
|
||||||
/// <param name="address">Start address of the range to synchronize</param>
|
/// <param name="address">Start address of the range to synchronize</param>
|
||||||
/// <param name="size">Size in bytes of the range to synchronize</param>
|
/// <param name="size">Size in bytes of the range to synchronize</param>
|
||||||
public void SynchronizeMemory(ulong address, ulong size)
|
public void SynchronizeMemory(ulong address, ulong size)
|
||||||
|
|
|
@ -76,10 +76,10 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
_cpStorageBuffers = new BuffersPerStage(Constants.TotalCpStorageBuffers);
|
_cpStorageBuffers = new BuffersPerStage(Constants.TotalCpStorageBuffers);
|
||||||
_cpUniformBuffers = new BuffersPerStage(Constants.TotalCpUniformBuffers);
|
_cpUniformBuffers = new BuffersPerStage(Constants.TotalCpUniformBuffers);
|
||||||
|
|
||||||
_gpStorageBuffers = new BuffersPerStage[Constants.TotalShaderStages];
|
_gpStorageBuffers = new BuffersPerStage[Constants.ShaderStages];
|
||||||
_gpUniformBuffers = new BuffersPerStage[Constants.TotalShaderStages];
|
_gpUniformBuffers = new BuffersPerStage[Constants.ShaderStages];
|
||||||
|
|
||||||
for (int index = 0; index < Constants.TotalShaderStages; index++)
|
for (int index = 0; index < Constants.ShaderStages; index++)
|
||||||
{
|
{
|
||||||
_gpStorageBuffers[index] = new BuffersPerStage(Constants.TotalGpStorageBuffers);
|
_gpStorageBuffers[index] = new BuffersPerStage(Constants.TotalGpStorageBuffers);
|
||||||
_gpUniformBuffers[index] = new BuffersPerStage(Constants.TotalGpUniformBuffers);
|
_gpUniformBuffers[index] = new BuffersPerStage(Constants.TotalGpUniformBuffers);
|
||||||
|
@ -387,7 +387,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Ensures that the compute engine bindings are visible to the host GPU.
|
/// Ensures that the compute engine bindings are visible to the host GPU.
|
||||||
/// This actually performs the binding using the host graphics API.
|
/// Note: this actually performs the binding using the host graphics API.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void CommitComputeBindings()
|
public void CommitComputeBindings()
|
||||||
{
|
{
|
||||||
|
@ -439,7 +439,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Ensures that the graphics engine bindings are visible to the host GPU.
|
/// Ensures that the graphics engine bindings are visible to the host GPU.
|
||||||
/// This actually performs the binding using the host graphics API.
|
/// Note: this actually performs the binding using the host graphics API.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void CommitBindings()
|
public void CommitBindings()
|
||||||
{
|
{
|
||||||
|
@ -543,11 +543,11 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This binds buffer into the host API, or updates data for already bound buffers.
|
/// This binds buffers into the host API, or updates data for already bound buffers.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="bindings">Bindings to bind or update</param>
|
/// <param name="bindings">Bindings to bind or update</param>
|
||||||
/// <param name="bind">True to bind, false to update</param>
|
/// <param name="bind">True to bind, false to update</param>
|
||||||
/// <param name="isStorage">True to bind as storage buffer, false to bind as uniform buffers</param>
|
/// <param name="isStorage">True to bind as storage buffer, false to bind as uniform buffer</param>
|
||||||
private void BindOrUpdateBuffers(BuffersPerStage[] bindings, bool bind, bool isStorage = false)
|
private void BindOrUpdateBuffers(BuffersPerStage[] bindings, bool bind, bool isStorage = false)
|
||||||
{
|
{
|
||||||
for (ShaderStage stage = ShaderStage.Vertex; stage <= ShaderStage.Fragment; stage++)
|
for (ShaderStage stage = ShaderStage.Vertex; stage <= ShaderStage.Fragment; stage++)
|
||||||
|
@ -608,8 +608,10 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Copy a buffer data from a given address to another.
|
/// Copy a buffer data from a given address to another.
|
||||||
/// This does a GPU side copy.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This does a GPU side copy.
|
||||||
|
/// </remarks>
|
||||||
/// <param name="srcVa">GPU virtual address of the copy source</param>
|
/// <param name="srcVa">GPU virtual address of the copy source</param>
|
||||||
/// <param name="dstVa">GPU virtual address of the copy destination</param>
|
/// <param name="dstVa">GPU virtual address of the copy destination</param>
|
||||||
/// <param name="size">Size in bytes of the copy</param>
|
/// <param name="size">Size in bytes of the copy</param>
|
||||||
|
|
|
@ -50,7 +50,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
/// Reads a structure from GPU mapped memory.
|
/// Reads a structure from GPU mapped memory.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">Type of the structure</typeparam>
|
/// <typeparam name="T">Type of the structure</typeparam>
|
||||||
/// <param name="gpuVa">GPU virtual address where the strcture is located</param>
|
/// <param name="gpuVa">GPU virtual address where the structure is located</param>
|
||||||
/// <returns>The structure at the specified memory location</returns>
|
/// <returns>The structure at the specified memory location</returns>
|
||||||
public T Read<T>(ulong gpuVa) where T : struct
|
public T Read<T>(ulong gpuVa) where T : struct
|
||||||
{
|
{
|
||||||
|
|
|
@ -39,8 +39,10 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Maps a given range of pages to the specified CPU virtual address.
|
/// Maps a given range of pages to the specified CPU virtual address.
|
||||||
/// All addresses and sizes must be page aligned.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// All addresses and sizes must be page aligned.
|
||||||
|
/// </remarks>
|
||||||
/// <param name="pa">CPU virtual address to map into</param>
|
/// <param name="pa">CPU virtual address to map into</param>
|
||||||
/// <param name="va">GPU virtual address to be mapped</param>
|
/// <param name="va">GPU virtual address to be mapped</param>
|
||||||
/// <param name="size">Size in bytes of the mapping</param>
|
/// <param name="size">Size in bytes of the mapping</param>
|
||||||
|
@ -59,7 +61,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Maps a given range of pages to a allocated GPU virtual address.
|
/// Maps a given range of pages to an allocated GPU virtual address.
|
||||||
/// The memory is automatically allocated by the memory manager.
|
/// The memory is automatically allocated by the memory manager.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="pa">CPU virtual address to map into</param>
|
/// <param name="pa">CPU virtual address to map into</param>
|
||||||
|
@ -84,7 +86,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Maps a given range of pages to a allocated GPU virtual address.
|
/// Maps a given range of pages to an allocated GPU virtual address.
|
||||||
/// The memory is automatically allocated by the memory manager.
|
/// The memory is automatically allocated by the memory manager.
|
||||||
/// This also ensures that the mapping is always done in the first 4GB of GPU address space.
|
/// This also ensures that the mapping is always done in the first 4GB of GPU address space.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -77,9 +77,11 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the first item on the list overlapping in memory with the specified item.
|
/// Gets the first item on the list overlapping in memory with the specified item.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
/// Despite the name, this has no ordering guarantees of the returned item.
|
/// Despite the name, this has no ordering guarantees of the returned item.
|
||||||
/// It only ensures that the item returned overlaps the specified item.
|
/// It only ensures that the item returned overlaps the specified item.
|
||||||
/// </summary>
|
/// </remarks>
|
||||||
/// <param name="item">Item to check for overlaps</param>
|
/// <param name="item">Item to check for overlaps</param>
|
||||||
/// <returns>The overlapping item, or the default value for the type if none found</returns>
|
/// <returns>The overlapping item, or the default value for the type if none found</returns>
|
||||||
public T FindFirstOverlap(T item)
|
public T FindFirstOverlap(T item)
|
||||||
|
@ -89,9 +91,11 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the first item on the list overlapping the specified memory range.
|
/// Gets the first item on the list overlapping the specified memory range.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
/// Despite the name, this has no ordering guarantees of the returned item.
|
/// Despite the name, this has no ordering guarantees of the returned item.
|
||||||
/// It only ensures that the item returned overlaps the specified memory range.
|
/// It only ensures that the item returned overlaps the specified memory range.
|
||||||
/// </summary>
|
/// </remarks>
|
||||||
/// <param name="address">Start address of the range</param>
|
/// <param name="address">Start address of the range</param>
|
||||||
/// <param name="size">Size in bytes or the rangee</param>
|
/// <param name="size">Size in bytes or the rangee</param>
|
||||||
/// <returns>The overlapping item, or the default value for the type if none found</returns>
|
/// <returns>The overlapping item, or the default value for the type if none found</returns>
|
||||||
|
@ -157,10 +161,12 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets all items overlapping with the specified item in memory.
|
/// Gets all items overlapping with the specified item in memory.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
/// This method only returns correct results if none of the items on the list overlaps with
|
/// This method only returns correct results if none of the items on the list overlaps with
|
||||||
/// each other. If that is not the case, this method should not be used.
|
/// each other. If that is not the case, this method should not be used.
|
||||||
/// This method is faster than the regular method to find all overlaps.
|
/// This method is faster than the regular method to find all overlaps.
|
||||||
/// </summary>
|
/// </remarks>
|
||||||
/// <param name="item">Item to check for overlaps</param>
|
/// <param name="item">Item to check for overlaps</param>
|
||||||
/// <param name="output">Output array where matches will be written. It is automatically resized to fit the results</param>
|
/// <param name="output">Output array where matches will be written. It is automatically resized to fit the results</param>
|
||||||
/// <returns>The number of overlapping items found</returns>
|
/// <returns>The number of overlapping items found</returns>
|
||||||
|
@ -171,10 +177,12 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets all items on the list overlapping the specified memory range.
|
/// Gets all items on the list overlapping the specified memory range.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
/// This method only returns correct results if none of the items on the list overlaps with
|
/// This method only returns correct results if none of the items on the list overlaps with
|
||||||
/// each other. If that is not the case, this method should not be used.
|
/// each other. If that is not the case, this method should not be used.
|
||||||
/// This method is faster than the regular method to find all overlaps.
|
/// This method is faster than the regular method to find all overlaps.
|
||||||
/// </summary>
|
/// </remarks>
|
||||||
/// <param name="address">Start address of the range</param>
|
/// <param name="address">Start address of the range</param>
|
||||||
/// <param name="size">Size in bytes or the rangee</param>
|
/// <param name="size">Size in bytes or the rangee</param>
|
||||||
/// <param name="output">Output array where matches will be written. It is automatically resized to fit the results</param>
|
/// <param name="output">Output array where matches will be written. It is automatically resized to fit the results</param>
|
||||||
|
|
|
@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public GraphicsShader()
|
public GraphicsShader()
|
||||||
{
|
{
|
||||||
Shaders = new CachedShader[5];
|
Shaders = new CachedShader[Constants.ShaderStages];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Graphics.GAL;
|
using Ryujinx.Graphics.GAL;
|
||||||
using Ryujinx.Graphics.Gpu.Image;
|
using Ryujinx.Graphics.Gpu.Image;
|
||||||
using Ryujinx.Graphics.Gpu.State;
|
using Ryujinx.Graphics.Gpu.State;
|
||||||
|
@ -45,8 +46,10 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a compute shader from the cache.
|
/// Gets a compute shader from the cache.
|
||||||
/// This automatically translates, compiles and adds the code to the cache if not present.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This automatically translates, compiles and adds the code to the cache if not present.
|
||||||
|
/// </remarks>
|
||||||
/// <param name="gpuVa">GPU virtual address of the binary shader code</param>
|
/// <param name="gpuVa">GPU virtual address of the binary shader code</param>
|
||||||
/// <param name="sharedMemorySize">Shared memory size of the compute shader</param>
|
/// <param name="sharedMemorySize">Shared memory size of the compute shader</param>
|
||||||
/// <param name="localSizeX">Local group size X of the computer shader</param>
|
/// <param name="localSizeX">Local group size X of the computer shader</param>
|
||||||
|
@ -93,8 +96,10 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a graphics shader program from the shader cache.
|
/// Gets a graphics shader program from the shader cache.
|
||||||
/// This includes all the specified shader stages.
|
/// This includes all the specified shader stages.
|
||||||
/// This automatically translates, compiles and adds the code to the cache if not present.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This automatically translates, compiles and adds the code to the cache if not present.
|
||||||
|
/// </remarks>
|
||||||
/// <param name="state">Current GPU state</param>
|
/// <param name="state">Current GPU state</param>
|
||||||
/// <param name="addresses">Addresses of the shaders for each stage</param>
|
/// <param name="addresses">Addresses of the shaders for each stage</param>
|
||||||
/// <returns>Compiled graphics shader code</returns>
|
/// <returns>Compiled graphics shader code</returns>
|
||||||
|
@ -246,28 +251,25 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
QueryInfoCallback queryInfo = (QueryInfoName info, int index) =>
|
int QueryInfo(QueryInfoName info, int index)
|
||||||
{
|
{
|
||||||
switch (info)
|
return info switch
|
||||||
{
|
{
|
||||||
case QueryInfoName.ComputeLocalSizeX:
|
QueryInfoName.ComputeLocalSizeX => localSizeX,
|
||||||
return localSizeX;
|
QueryInfoName.ComputeLocalSizeY => localSizeY,
|
||||||
case QueryInfoName.ComputeLocalSizeY:
|
QueryInfoName.ComputeLocalSizeZ => localSizeZ,
|
||||||
return localSizeY;
|
QueryInfoName.ComputeSharedMemorySize => sharedMemorySize,
|
||||||
case QueryInfoName.ComputeLocalSizeZ:
|
_ => QueryInfoCommon(info)
|
||||||
return localSizeZ;
|
};
|
||||||
case QueryInfoName.ComputeSharedMemorySize:
|
}
|
||||||
return sharedMemorySize;
|
|
||||||
}
|
|
||||||
|
|
||||||
return QueryInfoCommon(info);
|
TranslatorCallbacks callbacks = new TranslatorCallbacks(QueryInfo, PrintLog);
|
||||||
};
|
|
||||||
|
|
||||||
ShaderProgram program;
|
ShaderProgram program;
|
||||||
|
|
||||||
Span<byte> code = _context.MemoryAccessor.Read(gpuVa, MaxProgramSize);
|
Span<byte> code = _context.MemoryAccessor.Read(gpuVa, MaxProgramSize);
|
||||||
|
|
||||||
program = Translator.Translate(code, queryInfo, DefaultFlags | TranslationFlags.Compute);
|
program = Translator.Translate(code, callbacks, DefaultFlags | TranslationFlags.Compute);
|
||||||
|
|
||||||
int[] codeCached = MemoryMarshal.Cast<byte, int>(code.Slice(0, program.Size)).ToArray();
|
int[] codeCached = MemoryMarshal.Cast<byte, int>(code.Slice(0, program.Size)).ToArray();
|
||||||
|
|
||||||
|
@ -284,13 +286,15 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Translates the binary Maxwell shader code to something that the host API accepts.
|
/// Translates the binary Maxwell shader code to something that the host API accepts.
|
||||||
/// This will combine the "Vertex A" and "Vertex B" shader stages, if specified, into one shader.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This will combine the "Vertex A" and "Vertex B" shader stages, if specified, into one shader.
|
||||||
|
/// </remarks>
|
||||||
/// <param name="state">Current GPU state</param>
|
/// <param name="state">Current GPU state</param>
|
||||||
/// <param name="stage">Shader stage</param>
|
/// <param name="stage">Shader stage</param>
|
||||||
/// <param name="gpuVa">GPU virtual address of the shader code</param>
|
/// <param name="gpuVa">GPU virtual address of the shader code</param>
|
||||||
/// <param name="gpuVaA">Optional GPU virtual address of the "Vertex A" shader code</param>
|
/// <param name="gpuVaA">Optional GPU virtual address of the "Vertex A" shader code</param>
|
||||||
/// <returns></returns>
|
/// <returns>Compiled graphics shader code</returns>
|
||||||
private CachedShader TranslateGraphicsShader(GpuState state, ShaderStage stage, ulong gpuVa, ulong gpuVaA = 0)
|
private CachedShader TranslateGraphicsShader(GpuState state, ShaderStage stage, ulong gpuVa, ulong gpuVaA = 0)
|
||||||
{
|
{
|
||||||
if (gpuVa == 0)
|
if (gpuVa == 0)
|
||||||
|
@ -298,20 +302,18 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
return new CachedShader(null, null);
|
return new CachedShader(null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
QueryInfoCallback queryInfo = (QueryInfoName info, int index) =>
|
int QueryInfo(QueryInfoName info, int index)
|
||||||
{
|
{
|
||||||
switch (info)
|
return info switch
|
||||||
{
|
{
|
||||||
case QueryInfoName.IsTextureBuffer:
|
QueryInfoName.IsTextureBuffer => Convert.ToInt32(QueryIsTextureBuffer(state, (int)stage - 1, index)),
|
||||||
return Convert.ToInt32(QueryIsTextureBuffer(state, (int)stage - 1, index));
|
QueryInfoName.IsTextureRectangle => Convert.ToInt32(QueryIsTextureRectangle(state, (int)stage - 1, index)),
|
||||||
case QueryInfoName.IsTextureRectangle:
|
QueryInfoName.PrimitiveTopology => (int)GetPrimitiveTopology(),
|
||||||
return Convert.ToInt32(QueryIsTextureRectangle(state, (int)stage - 1, index));
|
_ => QueryInfoCommon(info)
|
||||||
case QueryInfoName.PrimitiveTopology:
|
};
|
||||||
return (int)GetPrimitiveTopology();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return QueryInfoCommon(info);
|
TranslatorCallbacks callbacks = new TranslatorCallbacks(QueryInfo, PrintLog);
|
||||||
};
|
|
||||||
|
|
||||||
ShaderProgram program;
|
ShaderProgram program;
|
||||||
|
|
||||||
|
@ -322,7 +324,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
Span<byte> codeA = _context.MemoryAccessor.Read(gpuVaA, MaxProgramSize);
|
Span<byte> codeA = _context.MemoryAccessor.Read(gpuVaA, MaxProgramSize);
|
||||||
Span<byte> codeB = _context.MemoryAccessor.Read(gpuVa, MaxProgramSize);
|
Span<byte> codeB = _context.MemoryAccessor.Read(gpuVa, MaxProgramSize);
|
||||||
|
|
||||||
program = Translator.Translate(codeA, codeB, queryInfo, DefaultFlags);
|
program = Translator.Translate(codeA, codeB, callbacks, DefaultFlags);
|
||||||
|
|
||||||
// TODO: We should also take "codeA" into account.
|
// TODO: We should also take "codeA" into account.
|
||||||
codeCached = MemoryMarshal.Cast<byte, int>(codeB.Slice(0, program.Size)).ToArray();
|
codeCached = MemoryMarshal.Cast<byte, int>(codeB.Slice(0, program.Size)).ToArray();
|
||||||
|
@ -342,7 +344,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
{
|
{
|
||||||
Span<byte> code = _context.MemoryAccessor.Read(gpuVa, MaxProgramSize);
|
Span<byte> code = _context.MemoryAccessor.Read(gpuVa, MaxProgramSize);
|
||||||
|
|
||||||
program = Translator.Translate(code, queryInfo, DefaultFlags);
|
program = Translator.Translate(code, callbacks, DefaultFlags);
|
||||||
|
|
||||||
codeCached = MemoryMarshal.Cast<byte, int>(code.Slice(0, program.Size)).ToArray();
|
codeCached = MemoryMarshal.Cast<byte, int>(code.Slice(0, program.Size)).ToArray();
|
||||||
|
|
||||||
|
@ -483,17 +485,21 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
/// <returns>Requested information</returns>
|
/// <returns>Requested information</returns>
|
||||||
private int QueryInfoCommon(QueryInfoName info)
|
private int QueryInfoCommon(QueryInfoName info)
|
||||||
{
|
{
|
||||||
switch (info)
|
return info switch
|
||||||
{
|
{
|
||||||
case QueryInfoName.MaximumViewportDimensions:
|
QueryInfoName.StorageBufferOffsetAlignment => _context.Capabilities.StorageBufferOffsetAlignment,
|
||||||
return _context.Capabilities.MaximumViewportDimensions;
|
QueryInfoName.SupportsNonConstantTextureOffset => Convert.ToInt32(_context.Capabilities.SupportsNonConstantTextureOffset),
|
||||||
case QueryInfoName.StorageBufferOffsetAlignment:
|
_ => 0
|
||||||
return _context.Capabilities.StorageBufferOffsetAlignment;
|
};
|
||||||
case QueryInfoName.SupportsNonConstantTextureOffset:
|
}
|
||||||
return Convert.ToInt32(_context.Capabilities.SupportsNonConstantTextureOffset);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
/// <summary>
|
||||||
|
/// Prints a warning from the shader code translator.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">Warning message</param>
|
||||||
|
private static void PrintLog(string message)
|
||||||
|
{
|
||||||
|
Logger.PrintWarning(LogClass.Gpu, $"Shader translator: {message}");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -187,7 +187,7 @@ namespace Ryujinx.Graphics.Gpu.State
|
||||||
/// </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>
|
||||||
/// <param name="m3">Third register offset</param>
|
/// <param name="m3">Third register offset</param>
|
||||||
/// <returns>True if any register was modified, false otherwise</returns>
|
/// <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)
|
||||||
{
|
{
|
||||||
|
@ -207,7 +207,7 @@ namespace Ryujinx.Graphics.Gpu.State
|
||||||
/// </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>
|
||||||
/// <param name="m3">Third register offset</param>
|
/// <param name="m3">Third register offset</param>
|
||||||
/// <param name="m4">Fourth register offset</param>
|
/// <param name="m4">Fourth register offset</param>
|
||||||
/// <returns>True if any register was modified, false otherwise</returns>
|
/// <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)
|
||||||
|
@ -230,7 +230,7 @@ namespace Ryujinx.Graphics.Gpu.State
|
||||||
/// </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>
|
||||||
/// <param name="m3">Third register offset</param>
|
/// <param name="m3">Third register offset</param>
|
||||||
/// <param name="m4">Fourth register offset</param>
|
/// <param name="m4">Fourth register offset</param>
|
||||||
/// <param name="m5">Fifth register offset</param>
|
/// <param name="m5">Fifth register offset</param>
|
||||||
/// <returns>True if any register was modified, false otherwise</returns>
|
/// <returns>True if any register was modified, false otherwise</returns>
|
||||||
|
|
|
@ -11,7 +11,7 @@ namespace Ryujinx.Graphics.Gpu.State
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Packs the split address into a 64-bits address value.
|
/// Packs the split address into a 64-bits address value.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns>The 64-bits address value</returns>
|
||||||
public ulong Pack()
|
public ulong Pack()
|
||||||
{
|
{
|
||||||
return Low | ((ulong)High << 32);
|
return Low | ((ulong)High << 32);
|
||||||
|
|
|
@ -3,6 +3,9 @@ namespace Ryujinx.Graphics.Gpu.State
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// GPU method offset.
|
/// GPU method offset.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This is indexed in 32 bits word.
|
||||||
|
/// </remarks>
|
||||||
enum MethodOffset
|
enum MethodOffset
|
||||||
{
|
{
|
||||||
I2mParams = 0x60,
|
I2mParams = 0x60,
|
||||||
|
|
|
@ -7,7 +7,6 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
{
|
{
|
||||||
private static Lazy<bool> _supportsAstcCompression = new Lazy<bool>(() => HasExtension("GL_KHR_texture_compression_astc_ldr"));
|
private static Lazy<bool> _supportsAstcCompression = new Lazy<bool>(() => HasExtension("GL_KHR_texture_compression_astc_ldr"));
|
||||||
|
|
||||||
private static Lazy<int> _maximumViewportDimensions = new Lazy<int>(() => GetLimit(All.MaxViewportDims));
|
|
||||||
private static Lazy<int> _maximumComputeSharedMemorySize = new Lazy<int>(() => GetLimit(All.MaxComputeSharedMemorySize));
|
private static Lazy<int> _maximumComputeSharedMemorySize = new Lazy<int>(() => GetLimit(All.MaxComputeSharedMemorySize));
|
||||||
private static Lazy<int> _storageBufferOffsetAlignment = new Lazy<int>(() => GetLimit(All.ShaderStorageBufferOffsetAlignment));
|
private static Lazy<int> _storageBufferOffsetAlignment = new Lazy<int>(() => GetLimit(All.ShaderStorageBufferOffsetAlignment));
|
||||||
|
|
||||||
|
@ -16,7 +15,6 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
public static bool SupportsAstcCompression => _supportsAstcCompression.Value;
|
public static bool SupportsAstcCompression => _supportsAstcCompression.Value;
|
||||||
public static bool SupportsNonConstantTextureOffset => _isNvidiaDriver.Value;
|
public static bool SupportsNonConstantTextureOffset => _isNvidiaDriver.Value;
|
||||||
|
|
||||||
public static int MaximumViewportDimensions => _maximumViewportDimensions.Value;
|
|
||||||
public static int MaximumComputeSharedMemorySize => _maximumComputeSharedMemorySize.Value;
|
public static int MaximumComputeSharedMemorySize => _maximumComputeSharedMemorySize.Value;
|
||||||
public static int StorageBufferOffsetAlignment => _storageBufferOffsetAlignment.Value;
|
public static int StorageBufferOffsetAlignment => _storageBufferOffsetAlignment.Value;
|
||||||
|
|
||||||
|
|
|
@ -64,7 +64,6 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
return new Capabilities(
|
return new Capabilities(
|
||||||
HwCapabilities.SupportsAstcCompression,
|
HwCapabilities.SupportsAstcCompression,
|
||||||
HwCapabilities.SupportsNonConstantTextureOffset,
|
HwCapabilities.SupportsNonConstantTextureOffset,
|
||||||
HwCapabilities.MaximumViewportDimensions,
|
|
||||||
HwCapabilities.MaximumComputeSharedMemorySize,
|
HwCapabilities.MaximumComputeSharedMemorySize,
|
||||||
HwCapabilities.StorageBufferOffsetAlignment);
|
HwCapabilities.StorageBufferOffsetAlignment);
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,6 +104,7 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
|
|
||||||
GL.TexParameter(target, TextureParameterName.TextureMaxLevel, maxLevel);
|
GL.TexParameter(target, TextureParameterName.TextureMaxLevel, maxLevel);
|
||||||
|
|
||||||
|
// TODO: This requires ARB_stencil_texturing, we should uncomment and test this.
|
||||||
// GL.TexParameter(target, TextureParameterName.DepthStencilTextureMode, (int)_info.DepthStencilMode.Convert());
|
// GL.TexParameter(target, TextureParameterName.DepthStencilTextureMode, (int)_info.DepthStencilMode.Convert());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,7 +119,11 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// TODO: Improve
|
// TODO: Most graphics APIs doesn't support creating a texture view from a compressed format
|
||||||
|
// with a non-compressed format (or vice-versa), however NVN seems to support it.
|
||||||
|
// So we emulate that here with a texture copy (see the first CopyTo overload).
|
||||||
|
// However right now it only does a single copy right after the view is created,
|
||||||
|
// so it doesn't work for all cases.
|
||||||
TextureView emulatedView = (TextureView)_renderer.CreateTexture(info);
|
TextureView emulatedView = (TextureView)_renderer.CreateTexture(info);
|
||||||
|
|
||||||
emulatedView._emulatedViewParent = this;
|
emulatedView._emulatedViewParent = this;
|
||||||
|
|
|
@ -91,10 +91,5 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||||
|
|
||||||
return indentation;
|
return indentation;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetTabString()
|
|
||||||
{
|
|
||||||
return Tab;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -86,6 +86,10 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
{
|
{
|
||||||
context.Barrier();
|
context.Barrier();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
context.Config.PrintLog($"Invalid barrier mode: {op.Mode}.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Ipa(EmitterContext context)
|
public static void Ipa(EmitterContext context)
|
||||||
|
@ -101,8 +105,6 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
|
|
||||||
Operand srcA = Attribute(op.AttributeOffset, iq);
|
Operand srcA = Attribute(op.AttributeOffset, iq);
|
||||||
|
|
||||||
Operand srcB = GetSrcB(context);
|
|
||||||
|
|
||||||
Operand res = context.FPSaturate(srcA, op.Saturate);
|
Operand res = context.FPSaturate(srcA, op.Saturate);
|
||||||
|
|
||||||
context.Copy(GetDest(context), res);
|
context.Copy(GetDest(context), res);
|
||||||
|
@ -128,7 +130,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
|
|
||||||
if (op.Size > IntegerSize.B64)
|
if (op.Size > IntegerSize.B64)
|
||||||
{
|
{
|
||||||
// TODO: Warning.
|
context.Config.PrintLog($"Invalid LDC size: {op.Size}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isSmallInt = op.Size < IntegerSize.B32;
|
bool isSmallInt = op.Size < IntegerSize.B32;
|
||||||
|
@ -156,7 +158,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
|
|
||||||
if (isSmallInt)
|
if (isSmallInt)
|
||||||
{
|
{
|
||||||
value = ExtractSmallInt(context, op.Size, wordOffset, value);
|
value = ExtractSmallInt(context, op.Size, bitOffset, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
context.Copy(Register(rd), value);
|
context.Copy(Register(rd), value);
|
||||||
|
@ -261,7 +263,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Not supported or invalid.
|
context.Config.PrintLog($"Invalid reduction type: {type}.");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case AtomicOp.BitwiseAnd:
|
case AtomicOp.BitwiseAnd:
|
||||||
|
@ -271,7 +273,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Not supported or invalid.
|
context.Config.PrintLog($"Invalid reduction type: {type}.");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case AtomicOp.BitwiseExclusiveOr:
|
case AtomicOp.BitwiseExclusiveOr:
|
||||||
|
@ -281,7 +283,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Not supported or invalid.
|
context.Config.PrintLog($"Invalid reduction type: {type}.");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case AtomicOp.BitwiseOr:
|
case AtomicOp.BitwiseOr:
|
||||||
|
@ -291,7 +293,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Not supported or invalid.
|
context.Config.PrintLog($"Invalid reduction type: {type}.");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case AtomicOp.Maximum:
|
case AtomicOp.Maximum:
|
||||||
|
@ -305,7 +307,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Not supported or invalid.
|
context.Config.PrintLog($"Invalid reduction type: {type}.");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case AtomicOp.Minimum:
|
case AtomicOp.Minimum:
|
||||||
|
@ -319,7 +321,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Not supported or invalid.
|
context.Config.PrintLog($"Invalid reduction type: {type}.");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -333,7 +335,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
|
|
||||||
if (op.Size > IntegerSize.B128)
|
if (op.Size > IntegerSize.B128)
|
||||||
{
|
{
|
||||||
// TODO: Warning.
|
context.Config.PrintLog($"Invalid load size: {op.Size}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isSmallInt = op.Size < IntegerSize.B32;
|
bool isSmallInt = op.Size < IntegerSize.B32;
|
||||||
|
@ -419,7 +421,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
|
|
||||||
if (op.Size > IntegerSize.B128)
|
if (op.Size > IntegerSize.B128)
|
||||||
{
|
{
|
||||||
// TODO: Warning.
|
context.Config.PrintLog($"Invalid store size: {op.Size}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isSmallInt = op.Size < IntegerSize.B32;
|
bool isSmallInt = op.Size < IntegerSize.B32;
|
||||||
|
|
|
@ -11,8 +11,6 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
{
|
{
|
||||||
public static void Mov(EmitterContext context)
|
public static void Mov(EmitterContext context)
|
||||||
{
|
{
|
||||||
OpCodeAlu op = (OpCodeAlu)context.CurrOp;
|
|
||||||
|
|
||||||
context.Copy(GetDest(context), GetSrcB(context));
|
context.Copy(GetDest(context), GetSrcB(context));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,7 +31,8 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
|
|
||||||
if (isCC)
|
if (isCC)
|
||||||
{
|
{
|
||||||
// TODO.
|
// TODO: Support Register to condition code flags copy.
|
||||||
|
context.Config.PrintLog("R2P.CC not implemented.");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -18,7 +18,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
|
|
||||||
if (type == SamplerType.None)
|
if (type == SamplerType.None)
|
||||||
{
|
{
|
||||||
// TODO: Error, encoding is invalid.
|
context.Config.PrintLog("Invalid image store sampler type.");
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -86,7 +86,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// TODO.
|
context.Config.PrintLog("Unsized image store not supported.");
|
||||||
}
|
}
|
||||||
|
|
||||||
Operand[] sources = sourcesList.ToArray();
|
Operand[] sources = sourcesList.ToArray();
|
||||||
|
@ -180,7 +180,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
|
|
||||||
if (type == SamplerType.None)
|
if (type == SamplerType.None)
|
||||||
{
|
{
|
||||||
// TODO: Error, encoding is invalid.
|
context.Config.PrintLog("Invalid texture sampler type.");
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -210,40 +210,40 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
{
|
{
|
||||||
switch (texsOp.Target)
|
switch (texsOp.Target)
|
||||||
{
|
{
|
||||||
case Decoders.TextureTarget.Texture1DLodZero:
|
case TextureTarget.Texture1DLodZero:
|
||||||
sourcesList.Add(Ra());
|
sourcesList.Add(Ra());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Decoders.TextureTarget.Texture2D:
|
case TextureTarget.Texture2D:
|
||||||
sourcesList.Add(Ra());
|
sourcesList.Add(Ra());
|
||||||
sourcesList.Add(Rb());
|
sourcesList.Add(Rb());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Decoders.TextureTarget.Texture2DLodZero:
|
case TextureTarget.Texture2DLodZero:
|
||||||
sourcesList.Add(Ra());
|
sourcesList.Add(Ra());
|
||||||
sourcesList.Add(Rb());
|
sourcesList.Add(Rb());
|
||||||
sourcesList.Add(ConstF(0));
|
sourcesList.Add(ConstF(0));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Decoders.TextureTarget.Texture2DLodLevel:
|
case TextureTarget.Texture2DLodLevel:
|
||||||
case Decoders.TextureTarget.Texture2DDepthCompare:
|
case TextureTarget.Texture2DDepthCompare:
|
||||||
case Decoders.TextureTarget.Texture3D:
|
case TextureTarget.Texture3D:
|
||||||
case Decoders.TextureTarget.TextureCube:
|
case TextureTarget.TextureCube:
|
||||||
sourcesList.Add(Ra());
|
sourcesList.Add(Ra());
|
||||||
sourcesList.Add(Ra());
|
sourcesList.Add(Ra());
|
||||||
sourcesList.Add(Rb());
|
sourcesList.Add(Rb());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Decoders.TextureTarget.Texture2DLodZeroDepthCompare:
|
case TextureTarget.Texture2DLodZeroDepthCompare:
|
||||||
case Decoders.TextureTarget.Texture3DLodZero:
|
case TextureTarget.Texture3DLodZero:
|
||||||
sourcesList.Add(Ra());
|
sourcesList.Add(Ra());
|
||||||
sourcesList.Add(Ra());
|
sourcesList.Add(Ra());
|
||||||
sourcesList.Add(Rb());
|
sourcesList.Add(Rb());
|
||||||
sourcesList.Add(ConstF(0));
|
sourcesList.Add(ConstF(0));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Decoders.TextureTarget.Texture2DLodLevelDepthCompare:
|
case TextureTarget.Texture2DLodLevelDepthCompare:
|
||||||
case Decoders.TextureTarget.TextureCubeLodLevel:
|
case TextureTarget.TextureCubeLodLevel:
|
||||||
sourcesList.Add(Ra());
|
sourcesList.Add(Ra());
|
||||||
sourcesList.Add(Ra());
|
sourcesList.Add(Ra());
|
||||||
sourcesList.Add(Rb());
|
sourcesList.Add(Rb());
|
||||||
|
@ -258,7 +258,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
|
|
||||||
if (type == SamplerType.None)
|
if (type == SamplerType.None)
|
||||||
{
|
{
|
||||||
// TODO: Error, encoding is invalid.
|
context.Config.PrintLog("Invalid texel fetch sampler type.");
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -742,8 +742,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
{
|
{
|
||||||
OpCodeTexture op = (OpCodeTexture)context.CurrOp;
|
OpCodeTexture op = (OpCodeTexture)context.CurrOp;
|
||||||
|
|
||||||
bool isBindless = (flags & TextureFlags.Bindless) != 0;
|
bool isBindless = (flags & TextureFlags.Bindless) != 0;
|
||||||
bool intCoords = (flags & TextureFlags.IntCoords) != 0;
|
|
||||||
|
|
||||||
if (op.Rd.IsRZ)
|
if (op.Rd.IsRZ)
|
||||||
{
|
{
|
||||||
|
@ -920,36 +919,36 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
throw new ArgumentException($"Invalid texture dimensions \"{dimensions}\".");
|
throw new ArgumentException($"Invalid texture dimensions \"{dimensions}\".");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static SamplerType ConvertSamplerType(Decoders.TextureTarget type)
|
private static SamplerType ConvertSamplerType(TextureTarget type)
|
||||||
{
|
{
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case Decoders.TextureTarget.Texture1DLodZero:
|
case TextureTarget.Texture1DLodZero:
|
||||||
return SamplerType.Texture1D;
|
return SamplerType.Texture1D;
|
||||||
|
|
||||||
case Decoders.TextureTarget.Texture2D:
|
case TextureTarget.Texture2D:
|
||||||
case Decoders.TextureTarget.Texture2DLodZero:
|
case TextureTarget.Texture2DLodZero:
|
||||||
case Decoders.TextureTarget.Texture2DLodLevel:
|
case TextureTarget.Texture2DLodLevel:
|
||||||
return SamplerType.Texture2D;
|
return SamplerType.Texture2D;
|
||||||
|
|
||||||
case Decoders.TextureTarget.Texture2DDepthCompare:
|
case TextureTarget.Texture2DDepthCompare:
|
||||||
case Decoders.TextureTarget.Texture2DLodLevelDepthCompare:
|
case TextureTarget.Texture2DLodLevelDepthCompare:
|
||||||
case Decoders.TextureTarget.Texture2DLodZeroDepthCompare:
|
case TextureTarget.Texture2DLodZeroDepthCompare:
|
||||||
return SamplerType.Texture2D | SamplerType.Shadow;
|
return SamplerType.Texture2D | SamplerType.Shadow;
|
||||||
|
|
||||||
case Decoders.TextureTarget.Texture2DArray:
|
case TextureTarget.Texture2DArray:
|
||||||
case Decoders.TextureTarget.Texture2DArrayLodZero:
|
case TextureTarget.Texture2DArrayLodZero:
|
||||||
return SamplerType.Texture2D | SamplerType.Array;
|
return SamplerType.Texture2D | SamplerType.Array;
|
||||||
|
|
||||||
case Decoders.TextureTarget.Texture2DArrayLodZeroDepthCompare:
|
case TextureTarget.Texture2DArrayLodZeroDepthCompare:
|
||||||
return SamplerType.Texture2D | SamplerType.Array | SamplerType.Shadow;
|
return SamplerType.Texture2D | SamplerType.Array | SamplerType.Shadow;
|
||||||
|
|
||||||
case Decoders.TextureTarget.Texture3D:
|
case TextureTarget.Texture3D:
|
||||||
case Decoders.TextureTarget.Texture3DLodZero:
|
case TextureTarget.Texture3DLodZero:
|
||||||
return SamplerType.Texture3D;
|
return SamplerType.Texture3D;
|
||||||
|
|
||||||
case Decoders.TextureTarget.TextureCube:
|
case TextureTarget.TextureCube:
|
||||||
case Decoders.TextureTarget.TextureCubeLodLevel:
|
case TextureTarget.TextureCubeLodLevel:
|
||||||
return SamplerType.TextureCube;
|
return SamplerType.TextureCube;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -987,22 +986,22 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
{
|
{
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case Decoders.TextureTarget.Texture1DLodZero:
|
case TextureTarget.Texture1DLodZero:
|
||||||
case Decoders.TextureTarget.Texture2DLodZero:
|
case TextureTarget.Texture2DLodZero:
|
||||||
case Decoders.TextureTarget.Texture2DLodLevel:
|
case TextureTarget.Texture2DLodLevel:
|
||||||
case Decoders.TextureTarget.Texture2DLodLevelDepthCompare:
|
case TextureTarget.Texture2DLodLevelDepthCompare:
|
||||||
case Decoders.TextureTarget.Texture2DLodZeroDepthCompare:
|
case TextureTarget.Texture2DLodZeroDepthCompare:
|
||||||
case Decoders.TextureTarget.Texture2DArrayLodZero:
|
case TextureTarget.Texture2DArrayLodZero:
|
||||||
case Decoders.TextureTarget.Texture2DArrayLodZeroDepthCompare:
|
case TextureTarget.Texture2DArrayLodZeroDepthCompare:
|
||||||
case Decoders.TextureTarget.Texture3DLodZero:
|
case TextureTarget.Texture3DLodZero:
|
||||||
case Decoders.TextureTarget.TextureCubeLodLevel:
|
case TextureTarget.TextureCubeLodLevel:
|
||||||
return TextureFlags.LodLevel;
|
return TextureFlags.LodLevel;
|
||||||
|
|
||||||
case Decoders.TextureTarget.Texture2D:
|
case TextureTarget.Texture2D:
|
||||||
case Decoders.TextureTarget.Texture2DDepthCompare:
|
case TextureTarget.Texture2DDepthCompare:
|
||||||
case Decoders.TextureTarget.Texture2DArray:
|
case TextureTarget.Texture2DArray:
|
||||||
case Decoders.TextureTarget.Texture3D:
|
case TextureTarget.Texture3D:
|
||||||
case Decoders.TextureTarget.TextureCube:
|
case TextureTarget.TextureCube:
|
||||||
return TextureFlags.None;
|
return TextureFlags.None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Invalid.
|
context.Config.PrintLog($"Invalid vote operation: {op.VoteOp}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!op.Rd.IsRZ)
|
if (!op.Rd.IsRZ)
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
namespace Ryujinx.Graphics.Shader
|
|
||||||
{
|
|
||||||
public delegate int QueryInfoCallback(QueryInfoName info, int index);
|
|
||||||
}
|
|
|
@ -8,7 +8,6 @@ namespace Ryujinx.Graphics.Shader
|
||||||
ComputeSharedMemorySize,
|
ComputeSharedMemorySize,
|
||||||
IsTextureBuffer,
|
IsTextureBuffer,
|
||||||
IsTextureRectangle,
|
IsTextureRectangle,
|
||||||
MaximumViewportDimensions,
|
|
||||||
PrimitiveTopology,
|
PrimitiveTopology,
|
||||||
StorageBufferOffsetAlignment,
|
StorageBufferOffsetAlignment,
|
||||||
SupportsNonConstantTextureOffset
|
SupportsNonConstantTextureOffset
|
||||||
|
|
|
@ -13,6 +13,8 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
|
|
||||||
private ShaderConfig _config;
|
private ShaderConfig _config;
|
||||||
|
|
||||||
|
public ShaderConfig Config => _config;
|
||||||
|
|
||||||
private List<Operation> _operations;
|
private List<Operation> _operations;
|
||||||
|
|
||||||
private Dictionary<ulong, Operand> _labels;
|
private Dictionary<ulong, Operand> _labels;
|
||||||
|
|
|
@ -16,30 +16,30 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
|
|
||||||
public TranslationFlags Flags { get; }
|
public TranslationFlags Flags { get; }
|
||||||
|
|
||||||
private QueryInfoCallback _queryInfoCallback;
|
private TranslatorCallbacks _callbacks;
|
||||||
|
|
||||||
public ShaderConfig(TranslationFlags flags, QueryInfoCallback queryInfoCallback)
|
public ShaderConfig(TranslationFlags flags, TranslatorCallbacks callbacks)
|
||||||
{
|
{
|
||||||
Stage = ShaderStage.Compute;
|
Stage = ShaderStage.Compute;
|
||||||
OutputTopology = OutputTopology.PointList;
|
OutputTopology = OutputTopology.PointList;
|
||||||
MaxOutputVertices = 0;
|
MaxOutputVertices = 0;
|
||||||
OmapTargets = null;
|
OmapTargets = null;
|
||||||
OmapSampleMask = false;
|
OmapSampleMask = false;
|
||||||
OmapDepth = false;
|
OmapDepth = false;
|
||||||
Flags = flags;
|
Flags = flags;
|
||||||
_queryInfoCallback = queryInfoCallback;
|
_callbacks = callbacks;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ShaderConfig(ShaderHeader header, TranslationFlags flags, QueryInfoCallback queryInfoCallback)
|
public ShaderConfig(ShaderHeader header, TranslationFlags flags, TranslatorCallbacks callbacks)
|
||||||
{
|
{
|
||||||
Stage = header.Stage;
|
Stage = header.Stage;
|
||||||
OutputTopology = header.OutputTopology;
|
OutputTopology = header.OutputTopology;
|
||||||
MaxOutputVertices = header.MaxOutputVertexCount;
|
MaxOutputVertices = header.MaxOutputVertexCount;
|
||||||
OmapTargets = header.OmapTargets;
|
OmapTargets = header.OmapTargets;
|
||||||
OmapSampleMask = header.OmapSampleMask;
|
OmapSampleMask = header.OmapSampleMask;
|
||||||
OmapDepth = header.OmapDepth;
|
OmapDepth = header.OmapDepth;
|
||||||
Flags = flags;
|
Flags = flags;
|
||||||
_queryInfoCallback = queryInfoCallback;
|
_callbacks = callbacks;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int GetDepthRegister()
|
public int GetDepthRegister()
|
||||||
|
@ -68,9 +68,9 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
|
|
||||||
public int QueryInfo(QueryInfoName info, int index = 0)
|
public int QueryInfo(QueryInfoName info, int index = 0)
|
||||||
{
|
{
|
||||||
if (_queryInfoCallback != null)
|
if (_callbacks.QueryInfo != null)
|
||||||
{
|
{
|
||||||
return _queryInfoCallback(info, index);
|
return _callbacks.QueryInfo(info, index);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -86,8 +86,6 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
return Convert.ToInt32(false);
|
return Convert.ToInt32(false);
|
||||||
case QueryInfoName.IsTextureRectangle:
|
case QueryInfoName.IsTextureRectangle:
|
||||||
return Convert.ToInt32(false);
|
return Convert.ToInt32(false);
|
||||||
case QueryInfoName.MaximumViewportDimensions:
|
|
||||||
return 0x8000;
|
|
||||||
case QueryInfoName.PrimitiveTopology:
|
case QueryInfoName.PrimitiveTopology:
|
||||||
return (int)InputTopology.Points;
|
return (int)InputTopology.Points;
|
||||||
case QueryInfoName.StorageBufferOffsetAlignment:
|
case QueryInfoName.StorageBufferOffsetAlignment:
|
||||||
|
@ -99,5 +97,10 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void PrintLog(string message)
|
||||||
|
{
|
||||||
|
_callbacks.PrintLog?.Invoke(message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -40,21 +40,17 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
return code.Slice(0, headerSize + (int)endAddress);
|
return code.Slice(0, headerSize + (int)endAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ShaderProgram Translate(Span<byte> code, QueryInfoCallback queryInfoCallback, TranslationFlags flags)
|
public static ShaderProgram Translate(Span<byte> code, TranslatorCallbacks callbacks, TranslationFlags flags)
|
||||||
{
|
{
|
||||||
bool compute = (flags & TranslationFlags.Compute) != 0;
|
Operation[] ops = DecodeShader(code, callbacks, flags, out ShaderConfig config, out int size);
|
||||||
|
|
||||||
Operation[] ops = DecodeShader(code, queryInfoCallback, flags, out ShaderConfig config, out int size);
|
|
||||||
|
|
||||||
return Translate(ops, config, size);
|
return Translate(ops, config, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ShaderProgram Translate(Span<byte> vpACode, Span<byte> vpBCode, QueryInfoCallback queryInfoCallback, TranslationFlags flags)
|
public static ShaderProgram Translate(Span<byte> vpACode, Span<byte> vpBCode, TranslatorCallbacks callbacks, TranslationFlags flags)
|
||||||
{
|
{
|
||||||
bool debugMode = (flags & TranslationFlags.DebugMode) != 0;
|
Operation[] vpAOps = DecodeShader(vpACode, callbacks, flags, out _, out _);
|
||||||
|
Operation[] vpBOps = DecodeShader(vpBCode, callbacks, flags, out ShaderConfig config, out int sizeB);
|
||||||
Operation[] vpAOps = DecodeShader(vpACode, queryInfoCallback, flags, out _, out _);
|
|
||||||
Operation[] vpBOps = DecodeShader(vpBCode, queryInfoCallback, flags, out ShaderConfig config, out int sizeB);
|
|
||||||
|
|
||||||
return Translate(Combine(vpAOps, vpBOps), config, sizeB);
|
return Translate(Combine(vpAOps, vpBOps), config, sizeB);
|
||||||
}
|
}
|
||||||
|
@ -94,34 +90,34 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Operation[] DecodeShader(
|
private static Operation[] DecodeShader(
|
||||||
Span<byte> code,
|
Span<byte> code,
|
||||||
QueryInfoCallback queryInfoCallback,
|
TranslatorCallbacks callbacks,
|
||||||
TranslationFlags flags,
|
TranslationFlags flags,
|
||||||
out ShaderConfig config,
|
out ShaderConfig config,
|
||||||
out int size)
|
out int size)
|
||||||
{
|
{
|
||||||
Block[] cfg;
|
Block[] cfg;
|
||||||
|
|
||||||
if ((flags & TranslationFlags.Compute) != 0)
|
if ((flags & TranslationFlags.Compute) != 0)
|
||||||
{
|
{
|
||||||
config = new ShaderConfig(flags, queryInfoCallback);
|
config = new ShaderConfig(flags, callbacks);
|
||||||
|
|
||||||
cfg = Decoder.Decode(code, 0);
|
cfg = Decoder.Decode(code, 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
config = new ShaderConfig(new ShaderHeader(code), flags, queryInfoCallback);
|
config = new ShaderConfig(new ShaderHeader(code), flags, callbacks);
|
||||||
|
|
||||||
cfg = Decoder.Decode(code, HeaderSize);
|
cfg = Decoder.Decode(code, HeaderSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cfg == null)
|
if (cfg == null)
|
||||||
{
|
{
|
||||||
// TODO: Error.
|
config.PrintLog("Invalid branch detected, failed to build CFG.");
|
||||||
|
|
||||||
size = 0;
|
size = 0;
|
||||||
|
|
||||||
return new Operation[0];
|
return Array.Empty<Operation>();
|
||||||
}
|
}
|
||||||
|
|
||||||
EmitterContext context = new EmitterContext(config);
|
EmitterContext context = new EmitterContext(config);
|
||||||
|
@ -156,6 +152,8 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
instName = "???";
|
instName = "???";
|
||||||
|
|
||||||
|
config.PrintLog($"Invalid instruction at 0x{op.Address:X6} (0x{op.RawOpCode:X16}).");
|
||||||
}
|
}
|
||||||
|
|
||||||
string dbgComment = $"0x{op.Address:X6}: 0x{op.RawOpCode:X16} {instName}";
|
string dbgComment = $"0x{op.Address:X6}: 0x{op.RawOpCode:X16} {instName}";
|
||||||
|
@ -210,10 +208,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
|
|
||||||
context.CurrOp = op;
|
context.CurrOp = op;
|
||||||
|
|
||||||
if (op.Emitter != null)
|
op.Emitter?.Invoke(context);
|
||||||
{
|
|
||||||
op.Emitter(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (predSkipLbl != null)
|
if (predSkipLbl != null)
|
||||||
{
|
{
|
||||||
|
|
17
Ryujinx.Graphics.Shader/Translation/TranslatorCallbacks.cs
Normal file
17
Ryujinx.Graphics.Shader/Translation/TranslatorCallbacks.cs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ryujinx.Graphics.Shader.Translation
|
||||||
|
{
|
||||||
|
public struct TranslatorCallbacks
|
||||||
|
{
|
||||||
|
internal Func<QueryInfoName, int, int> QueryInfo { get; }
|
||||||
|
|
||||||
|
internal Action<string> PrintLog { get; }
|
||||||
|
|
||||||
|
public TranslatorCallbacks(Func<QueryInfoName, int, int> queryInfoCallback, Action<string> printLogCallback)
|
||||||
|
{
|
||||||
|
QueryInfo = queryInfoCallback;
|
||||||
|
PrintLog = printLogCallback;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -405,14 +405,14 @@ namespace Ryujinx.Ui
|
||||||
/// <returns>An <see cref="IAalOutput"/> supported by this machine</returns>
|
/// <returns>An <see cref="IAalOutput"/> supported by this machine</returns>
|
||||||
private static IAalOutput InitializeAudioEngine()
|
private static IAalOutput InitializeAudioEngine()
|
||||||
{
|
{
|
||||||
/*if (SoundIoAudioOut.IsSupported)
|
if (OpenALAudioOut.IsSupported)
|
||||||
{
|
|
||||||
return new SoundIoAudioOut();
|
|
||||||
}
|
|
||||||
else*/ if (OpenALAudioOut.IsSupported)
|
|
||||||
{
|
{
|
||||||
return new OpenALAudioOut();
|
return new OpenALAudioOut();
|
||||||
}
|
}
|
||||||
|
else if (SoundIoAudioOut.IsSupported)
|
||||||
|
{
|
||||||
|
return new SoundIoAudioOut();
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return new DummyAudioOut();
|
return new DummyAudioOut();
|
||||||
|
|
Loading…
Reference in a new issue