mirror of
https://git.ryujinx.app/projects/Kenji-NX.git
synced 2026-10-04 18:38:52 +02:00
Implement buffer texture alignment
This commit is contained in:
@@ -32,6 +32,7 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
public readonly bool SupportsGeometryShader;
|
public readonly bool SupportsGeometryShader;
|
||||||
public readonly bool SupportsGeometryShaderPassthrough;
|
public readonly bool SupportsGeometryShaderPassthrough;
|
||||||
public readonly bool SupportsTransformFeedback;
|
public readonly bool SupportsTransformFeedback;
|
||||||
|
public readonly bool SupportsImageBufferPixelAlignment;
|
||||||
public readonly bool SupportsImageLoadFormatted;
|
public readonly bool SupportsImageLoadFormatted;
|
||||||
public readonly bool SupportsLayerVertexTessellation;
|
public readonly bool SupportsLayerVertexTessellation;
|
||||||
public readonly bool SupportsMismatchingViewFormat;
|
public readonly bool SupportsMismatchingViewFormat;
|
||||||
@@ -43,6 +44,7 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
public readonly bool SupportsShaderBarrierDivergence;
|
public readonly bool SupportsShaderBarrierDivergence;
|
||||||
public readonly bool SupportsShaderFloat64;
|
public readonly bool SupportsShaderFloat64;
|
||||||
public readonly bool SupportsShaderNonUniformIndexing;
|
public readonly bool SupportsShaderNonUniformIndexing;
|
||||||
|
public readonly bool SupportsTextureBufferPixelAlignment;
|
||||||
public readonly bool SupportsTextureGatherOffsets;
|
public readonly bool SupportsTextureGatherOffsets;
|
||||||
public readonly bool SupportsTextureShadowLod;
|
public readonly bool SupportsTextureShadowLod;
|
||||||
public readonly bool SupportsVertexStoreAndAtomics;
|
public readonly bool SupportsVertexStoreAndAtomics;
|
||||||
@@ -101,6 +103,7 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
bool supportsGeometryShader,
|
bool supportsGeometryShader,
|
||||||
bool supportsGeometryShaderPassthrough,
|
bool supportsGeometryShaderPassthrough,
|
||||||
bool supportsTransformFeedback,
|
bool supportsTransformFeedback,
|
||||||
|
bool supportsImageBufferPixelAlignment,
|
||||||
bool supportsImageLoadFormatted,
|
bool supportsImageLoadFormatted,
|
||||||
bool supportsLayerVertexTessellation,
|
bool supportsLayerVertexTessellation,
|
||||||
bool supportsMismatchingViewFormat,
|
bool supportsMismatchingViewFormat,
|
||||||
@@ -112,6 +115,7 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
bool supportsShaderBarrierDivergence,
|
bool supportsShaderBarrierDivergence,
|
||||||
bool supportsShaderFloat64,
|
bool supportsShaderFloat64,
|
||||||
bool supportsShaderNonUniformIndexing,
|
bool supportsShaderNonUniformIndexing,
|
||||||
|
bool supportsTextureBufferPixelAlignment,
|
||||||
bool supportsTextureGatherOffsets,
|
bool supportsTextureGatherOffsets,
|
||||||
bool supportsTextureShadowLod,
|
bool supportsTextureShadowLod,
|
||||||
bool supportsVertexStoreAndAtomics,
|
bool supportsVertexStoreAndAtomics,
|
||||||
@@ -164,6 +168,7 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
SupportsGeometryShader = supportsGeometryShader;
|
SupportsGeometryShader = supportsGeometryShader;
|
||||||
SupportsGeometryShaderPassthrough = supportsGeometryShaderPassthrough;
|
SupportsGeometryShaderPassthrough = supportsGeometryShaderPassthrough;
|
||||||
SupportsTransformFeedback = supportsTransformFeedback;
|
SupportsTransformFeedback = supportsTransformFeedback;
|
||||||
|
SupportsImageBufferPixelAlignment = supportsImageBufferPixelAlignment;
|
||||||
SupportsImageLoadFormatted = supportsImageLoadFormatted;
|
SupportsImageLoadFormatted = supportsImageLoadFormatted;
|
||||||
SupportsLayerVertexTessellation = supportsLayerVertexTessellation;
|
SupportsLayerVertexTessellation = supportsLayerVertexTessellation;
|
||||||
SupportsMismatchingViewFormat = supportsMismatchingViewFormat;
|
SupportsMismatchingViewFormat = supportsMismatchingViewFormat;
|
||||||
@@ -175,6 +180,7 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
SupportsShaderBarrierDivergence = supportsShaderBarrierDivergence;
|
SupportsShaderBarrierDivergence = supportsShaderBarrierDivergence;
|
||||||
SupportsShaderFloat64 = supportsShaderFloat64;
|
SupportsShaderFloat64 = supportsShaderFloat64;
|
||||||
SupportsShaderNonUniformIndexing = supportsShaderNonUniformIndexing;
|
SupportsShaderNonUniformIndexing = supportsShaderNonUniformIndexing;
|
||||||
|
SupportsTextureBufferPixelAlignment = supportsTextureBufferPixelAlignment;
|
||||||
SupportsTextureGatherOffsets = supportsTextureGatherOffsets;
|
SupportsTextureGatherOffsets = supportsTextureGatherOffsets;
|
||||||
SupportsTextureShadowLod = supportsTextureShadowLod;
|
SupportsTextureShadowLod = supportsTextureShadowLod;
|
||||||
SupportsVertexStoreAndAtomics = supportsVertexStoreAndAtomics;
|
SupportsVertexStoreAndAtomics = supportsVertexStoreAndAtomics;
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using Ryujinx.Graphics.Gpu.Engine.Types;
|
|||||||
using Ryujinx.Graphics.Gpu.Memory;
|
using Ryujinx.Graphics.Gpu.Memory;
|
||||||
using Ryujinx.Graphics.Gpu.Shader;
|
using Ryujinx.Graphics.Gpu.Shader;
|
||||||
using Ryujinx.Graphics.Shader;
|
using Ryujinx.Graphics.Shader;
|
||||||
|
using Ryujinx.Memory.Range;
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
@@ -67,6 +68,9 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
|
|
||||||
private int _lastFragmentTotal;
|
private int _lastFragmentTotal;
|
||||||
|
|
||||||
|
private readonly int _bufferTextureAlignment;
|
||||||
|
private readonly int _bufferImageAlignment;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Constructs a new instance of the texture bindings manager.
|
/// Constructs a new instance of the texture bindings manager.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -108,6 +112,10 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
}
|
}
|
||||||
|
|
||||||
_textureCounts = [];
|
_textureCounts = [];
|
||||||
|
|
||||||
|
int alignment = context.Capabilities.TextureBufferOffsetAlignment;
|
||||||
|
_bufferTextureAlignment = context.Capabilities.SupportsTextureBufferPixelAlignment ? 0 : alignment;
|
||||||
|
_bufferImageAlignment = context.Capabilities.SupportsImageBufferPixelAlignment ? 0 : alignment;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -521,10 +529,12 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
|
|
||||||
if (hostTexture != null && texture.Target == Target.TextureBuffer)
|
if (hostTexture != null && texture.Target == Target.TextureBuffer)
|
||||||
{
|
{
|
||||||
|
MultiRange range = GetAlignedBufferTextureRange(texture, index, stageIndex, false);
|
||||||
|
|
||||||
// Ensure that the buffer texture is using the correct buffer as storage.
|
// Ensure that the buffer texture is using the correct buffer as storage.
|
||||||
// Buffers are frequently re-created to accommodate larger data, so we need to re-bind
|
// Buffers are frequently re-created to accommodate larger data, so we need to re-bind
|
||||||
// to ensure we're not using a old buffer that was already deleted.
|
// to ensure we're not using a old buffer that was already deleted.
|
||||||
_channel.BufferManager.SetBufferTextureStorage(stage, hostTexture, texture.Range, bindingInfo, false);
|
_channel.BufferManager.SetBufferTextureStorage(stage, hostTexture, range, bindingInfo, false);
|
||||||
|
|
||||||
// Cache is not used for buffer texture, it must always rebind.
|
// Cache is not used for buffer texture, it must always rebind.
|
||||||
state.CachedTexture = null;
|
state.CachedTexture = null;
|
||||||
@@ -659,7 +669,9 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
// Buffers are frequently re-created to accommodate larger data, so we need to re-bind
|
// Buffers are frequently re-created to accommodate larger data, so we need to re-bind
|
||||||
// to ensure we're not using a old buffer that was already deleted.
|
// to ensure we're not using a old buffer that was already deleted.
|
||||||
|
|
||||||
_channel.BufferManager.SetBufferTextureStorage(stage, hostTexture, texture.Range, bindingInfo, true);
|
MultiRange range = GetAlignedBufferTextureRange(texture, index, stageIndex, true);
|
||||||
|
|
||||||
|
_channel.BufferManager.SetBufferTextureStorage(stage, hostTexture, range, bindingInfo, true);
|
||||||
|
|
||||||
// Cache is not used for buffer texture, it must always rebind.
|
// Cache is not used for buffer texture, it must always rebind.
|
||||||
state.CachedTexture = null;
|
state.CachedTexture = null;
|
||||||
@@ -692,6 +704,61 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
return specStateMatches;
|
return specStateMatches;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the aligned address of the texture according to the host requirements.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="texture">Texture to have its address aligned</param>
|
||||||
|
/// <param name="index">Index of the texture in the shader</param>
|
||||||
|
/// <param name="stageIndex">Index of the shader stage</param>
|
||||||
|
/// <param name="isImage">True if the texture is bound as image, false for sampled textures</param>
|
||||||
|
/// <returns>Aligned address and size of the buffer texture</returns>
|
||||||
|
private MultiRange GetAlignedBufferTextureRange(Texture texture, int index, int stageIndex, bool isImage)
|
||||||
|
{
|
||||||
|
MultiRange range = texture.Range;
|
||||||
|
int alignment = isImage ? _bufferImageAlignment : _bufferTextureAlignment;
|
||||||
|
|
||||||
|
if (alignment != 0)
|
||||||
|
{
|
||||||
|
MemoryRange firstRange = range.GetSubRange(0);
|
||||||
|
ulong misalign = firstRange.Address & ((ulong)alignment - 1);
|
||||||
|
int offset = misalign != 0 ? (int)misalign / texture.Info.FormatInfo.BytesPerPixel : 0;
|
||||||
|
|
||||||
|
if (misalign != 0)
|
||||||
|
{
|
||||||
|
firstRange = new MemoryRange(firstRange.Address - misalign, firstRange.Size + misalign);
|
||||||
|
|
||||||
|
if (range.Count > 1)
|
||||||
|
{
|
||||||
|
MemoryRange[] ranges = new MemoryRange[range.Count];
|
||||||
|
|
||||||
|
ranges[0] = firstRange;
|
||||||
|
|
||||||
|
for (int i = 1; i < range.Count; i++)
|
||||||
|
{
|
||||||
|
ranges[i] = range.GetSubRange(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
range = new MultiRange(ranges);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
range = new MultiRange(firstRange.Address, firstRange.Size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isImage)
|
||||||
|
{
|
||||||
|
_context.SupportBufferUpdater.UpdateBufferImageOffset(stageIndex, index, offset);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_context.SupportBufferUpdater.UpdateBufferTextureOffset(stageIndex, index, offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return range;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the texture descriptor for a given texture handle.
|
/// Gets the texture descriptor for a given texture handle.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -129,6 +129,38 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates the offset used for accessing buffer textures that are not aligned to the host requirements.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stageIndex">Index of the shader stage where the texture is used</param>
|
||||||
|
/// <param name="bindingIndex">Index of the texture binding in the shader</param>
|
||||||
|
/// <param name="offset">Offset for the misaligned part of the address</param>
|
||||||
|
public void UpdateBufferTextureOffset(int stageIndex, int bindingIndex, int offset)
|
||||||
|
{
|
||||||
|
if (_data.BufferTextureOffset[stageIndex][bindingIndex].X != offset)
|
||||||
|
{
|
||||||
|
_data.BufferTextureOffset[stageIndex][bindingIndex].X = offset;
|
||||||
|
int index = stageIndex * SupportBuffer.TextureCount + bindingIndex;
|
||||||
|
MarkDirty(SupportBuffer.BufferTextureOffsetOffset + index * sizeof(int) * 4, sizeof(int));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates the offset used for accessing buffer images that are not aligned to the host requirements.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stageIndex">Index of the shader stage where the image is used</param>
|
||||||
|
/// <param name="bindingIndex">Index of the image binding in the shader</param>
|
||||||
|
/// <param name="offset">Offset for the misaligned part of the address</param>
|
||||||
|
public void UpdateBufferImageOffset(int stageIndex, int bindingIndex, int offset)
|
||||||
|
{
|
||||||
|
if (_data.BufferTextureOffset[stageIndex][bindingIndex].Y != offset)
|
||||||
|
{
|
||||||
|
_data.BufferTextureOffset[stageIndex][bindingIndex].Y = offset;
|
||||||
|
int index = stageIndex * SupportBuffer.TextureCount + bindingIndex;
|
||||||
|
MarkDirty(SupportBuffer.BufferTextureOffsetOffset + index * sizeof(int) * 4 + sizeof(int), sizeof(int));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets whether the format of a given render target is a BGRA format.
|
/// Sets whether the format of a given render target is a BGRA format.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -207,6 +207,10 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
|
|
||||||
public bool QueryHostSupportsBgraFormat() => _context.Capabilities.SupportsBgraFormat;
|
public bool QueryHostSupportsBgraFormat() => _context.Capabilities.SupportsBgraFormat;
|
||||||
|
|
||||||
|
public bool QueryHostSupportsBufferImagePixelAlignment() => _context.Capabilities.SupportsImageBufferPixelAlignment;
|
||||||
|
|
||||||
|
public bool QueryHostSupportsBufferTexturePixelAlignment() => _context.Capabilities.SupportsTextureBufferPixelAlignment;
|
||||||
|
|
||||||
public bool QueryHostSupportsFragmentShaderInterlock() => _context.Capabilities.SupportsFragmentShaderInterlock;
|
public bool QueryHostSupportsFragmentShaderInterlock() => _context.Capabilities.SupportsFragmentShaderInterlock;
|
||||||
|
|
||||||
public bool QueryHostSupportsFragmentShaderOrderingIntel() => _context.Capabilities.SupportsFragmentShaderOrderingIntel;
|
public bool QueryHostSupportsFragmentShaderOrderingIntel() => _context.Capabilities.SupportsFragmentShaderOrderingIntel;
|
||||||
|
|||||||
@@ -174,6 +174,7 @@ namespace Ryujinx.Graphics.OpenGL
|
|||||||
supportsGeometryShader: true,
|
supportsGeometryShader: true,
|
||||||
supportsGeometryShaderPassthrough: HwCapabilities.SupportsGeometryShaderPassthrough,
|
supportsGeometryShaderPassthrough: HwCapabilities.SupportsGeometryShaderPassthrough,
|
||||||
supportsTransformFeedback: true,
|
supportsTransformFeedback: true,
|
||||||
|
supportsImageBufferPixelAlignment: false,
|
||||||
supportsImageLoadFormatted: HwCapabilities.SupportsImageLoadFormatted,
|
supportsImageLoadFormatted: HwCapabilities.SupportsImageLoadFormatted,
|
||||||
supportsLayerVertexTessellation: HwCapabilities.SupportsShaderViewportLayerArray,
|
supportsLayerVertexTessellation: HwCapabilities.SupportsShaderViewportLayerArray,
|
||||||
supportsMismatchingViewFormat: HwCapabilities.SupportsMismatchingViewFormat,
|
supportsMismatchingViewFormat: HwCapabilities.SupportsMismatchingViewFormat,
|
||||||
@@ -185,6 +186,7 @@ namespace Ryujinx.Graphics.OpenGL
|
|||||||
supportsShaderBarrierDivergence: !(intelWindows || intelUnix),
|
supportsShaderBarrierDivergence: !(intelWindows || intelUnix),
|
||||||
supportsShaderFloat64: true,
|
supportsShaderFloat64: true,
|
||||||
supportsShaderNonUniformIndexing: false,
|
supportsShaderNonUniformIndexing: false,
|
||||||
|
supportsTextureBufferPixelAlignment: false,
|
||||||
supportsTextureGatherOffsets: true,
|
supportsTextureGatherOffsets: true,
|
||||||
supportsTextureShadowLod: HwCapabilities.SupportsTextureShadowLod,
|
supportsTextureShadowLod: HwCapabilities.SupportsTextureShadowLod,
|
||||||
supportsVertexStoreAndAtomics: true,
|
supportsVertexStoreAndAtomics: true,
|
||||||
|
|||||||
@@ -234,6 +234,24 @@ namespace Ryujinx.Graphics.Shader
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queries host support for buffer image access with the buffer offset aligned to a single pixel rather than a fixed alignment.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>True if the host supports buffer image access with pixel alignment, false otherwise</returns>
|
||||||
|
bool QueryHostSupportsBufferImagePixelAlignment()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queries host support for buffer texture access with the buffer offset aligned to a single pixel rather than a fixed alignment.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>True if the host supports buffer texture access with pixel alignment, false otherwise</returns>
|
||||||
|
bool QueryHostSupportsBufferTexturePixelAlignment()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Queries host support for fragment shader ordering critical sections on the shader code.
|
/// Queries host support for fragment shader ordering critical sections on the shader code.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ namespace Ryujinx.Graphics.Shader
|
|||||||
RenderScale,
|
RenderScale,
|
||||||
TfeOffset,
|
TfeOffset,
|
||||||
TfeVertexCount,
|
TfeVertexCount,
|
||||||
|
BufferTextureOffset,
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct SupportBuffer
|
public struct SupportBuffer
|
||||||
@@ -42,10 +43,13 @@ namespace Ryujinx.Graphics.Shader
|
|||||||
public static readonly int ComputeRenderScaleOffset;
|
public static readonly int ComputeRenderScaleOffset;
|
||||||
public static readonly int TfeOffsetOffset;
|
public static readonly int TfeOffsetOffset;
|
||||||
public static readonly int TfeVertexCountOffset;
|
public static readonly int TfeVertexCountOffset;
|
||||||
|
public static readonly int BufferTextureOffsetOffset;
|
||||||
|
|
||||||
public const int FragmentIsBgraCount = 8;
|
public const int FragmentIsBgraCount = 8;
|
||||||
|
public const int TextureCount = 64;
|
||||||
|
|
||||||
// One for the render target, 64 for the textures, and 8 for the images.
|
// One for the render target, 64 for the textures, and 8 for the images.
|
||||||
public const int RenderScaleMaxCount = 1 + 64 + 8;
|
public const int RenderScaleMaxCount = 1 + TextureCount + 8;
|
||||||
|
|
||||||
private static int OffsetOf<T>(ref SupportBuffer storage, ref T target)
|
private static int OffsetOf<T>(ref SupportBuffer storage, ref T target)
|
||||||
{
|
{
|
||||||
@@ -68,6 +72,7 @@ namespace Ryujinx.Graphics.Shader
|
|||||||
ComputeRenderScaleOffset = GraphicsRenderScaleOffset + FieldSize;
|
ComputeRenderScaleOffset = GraphicsRenderScaleOffset + FieldSize;
|
||||||
TfeOffsetOffset = OffsetOf(ref instance, ref instance.TfeOffset);
|
TfeOffsetOffset = OffsetOf(ref instance, ref instance.TfeOffset);
|
||||||
TfeVertexCountOffset = OffsetOf(ref instance, ref instance.TfeVertexCount);
|
TfeVertexCountOffset = OffsetOf(ref instance, ref instance.TfeVertexCount);
|
||||||
|
BufferTextureOffsetOffset = OffsetOf(ref instance, ref instance.BufferTextureOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static StructureType GetStructureType()
|
internal static StructureType GetStructureType()
|
||||||
@@ -80,7 +85,8 @@ namespace Ryujinx.Graphics.Shader
|
|||||||
new StructureField(AggregateType.S32, "frag_scale_count"),
|
new StructureField(AggregateType.S32, "frag_scale_count"),
|
||||||
new StructureField(AggregateType.Array | AggregateType.FP32, "render_scale", RenderScaleMaxCount),
|
new StructureField(AggregateType.Array | AggregateType.FP32, "render_scale", RenderScaleMaxCount),
|
||||||
new StructureField(AggregateType.Vector4 | AggregateType.S32, "tfe_offset"),
|
new StructureField(AggregateType.Vector4 | AggregateType.S32, "tfe_offset"),
|
||||||
new StructureField(AggregateType.S32, "tfe_vertex_count")
|
new StructureField(AggregateType.S32, "tfe_vertex_count"),
|
||||||
|
new StructureField(AggregateType.Array | AggregateType.Vector2 | AggregateType.S32, "buffer_texture_offset")
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,5 +101,7 @@ namespace Ryujinx.Graphics.Shader
|
|||||||
|
|
||||||
public Vector4<int> TfeOffset;
|
public Vector4<int> TfeOffset;
|
||||||
public Vector4<int> TfeVertexCount;
|
public Vector4<int> TfeVertexCount;
|
||||||
|
|
||||||
|
public Array5<Array64<Vector4<int>>> BufferTextureOffset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
||||||
|
using Ryujinx.Graphics.Shader.Translation.Optimizations;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
|
using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
|
||||||
@@ -27,7 +28,19 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
|||||||
|
|
||||||
if (texOp.Type == SamplerType.TextureBuffer && !context.GpuAccessor.QueryHostSupportsSnormBufferTextureFormat())
|
if (texOp.Type == SamplerType.TextureBuffer && !context.GpuAccessor.QueryHostSupportsSnormBufferTextureFormat())
|
||||||
{
|
{
|
||||||
node = InsertSnormNormalization(node, context.ResourceManager, context.GpuAccessor);
|
if (!context.GpuAccessor.QueryHostSupportsSnormBufferTextureFormat())
|
||||||
|
{
|
||||||
|
node = InsertSnormNormalization(node, context.ResourceManager, context.GpuAccessor);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!context.GpuAccessor.QueryHostSupportsBufferTexturePixelAlignment())
|
||||||
|
{
|
||||||
|
node = InsertCoordOffset(node, context.ResourceManager, context.Stage, isImage: false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!context.GpuAccessor.QueryHostSupportsBufferTexturePixelAlignment() && texOp.Inst.IsImage())
|
||||||
|
{
|
||||||
|
node = InsertCoordOffset(node, context.ResourceManager, context.Stage, isImage: true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -278,6 +291,87 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static LinkedListNode<INode> InsertCoordOffset(LinkedListNode<INode> node, ResourceManager resourceManager, ShaderStage stage, bool isImage)
|
||||||
|
{
|
||||||
|
// Some GPUs have fixed alignment requirements for buffer textures.
|
||||||
|
// For those cases, we bind the aligned buffer offset, and apply the remaining offset on the shader.
|
||||||
|
|
||||||
|
TextureOperation texOp = (TextureOperation)node.Value;
|
||||||
|
|
||||||
|
if ((texOp.Type & SamplerType.Mask) != SamplerType.TextureBuffer)
|
||||||
|
{
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
Operand[] sources = new Operand[texOp.SourcesCount];
|
||||||
|
|
||||||
|
for (int i = 0; i < texOp.SourcesCount; i++)
|
||||||
|
{
|
||||||
|
sources[i] = texOp.GetSource(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0;
|
||||||
|
bool isIndexed = resourceManager.IsArrayOfTexturesOrImages(texOp.Binding, isImage);
|
||||||
|
|
||||||
|
int coordsIndex = isBindless || isIndexed ? 1 : 0;
|
||||||
|
|
||||||
|
Operand[] dests = new Operand[texOp.DestsCount];
|
||||||
|
|
||||||
|
for (int i = 0; i < texOp.DestsCount; i++)
|
||||||
|
{
|
||||||
|
dests[i] = texOp.GetDest(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
LinkedListNode<INode> oldNode = node;
|
||||||
|
|
||||||
|
Operand source = sources[coordsIndex];
|
||||||
|
Operand offset = Local();
|
||||||
|
Operand coordPlusOffset = Local();
|
||||||
|
|
||||||
|
int stageIndex = stage switch
|
||||||
|
{
|
||||||
|
ShaderStage.TessellationControl => 1,
|
||||||
|
ShaderStage.TessellationEvaluation => 2,
|
||||||
|
ShaderStage.Geometry => 3,
|
||||||
|
ShaderStage.Fragment => 4,
|
||||||
|
_ => 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
int bindingIndex = isImage
|
||||||
|
? resourceManager.FindImageDescriptorIndex(texOp.Binding)
|
||||||
|
: resourceManager.FindTextureDescriptorIndex(texOp.Binding);
|
||||||
|
|
||||||
|
node.List.AddBefore(node, new Operation(
|
||||||
|
Instruction.Load,
|
||||||
|
StorageKind.ConstantBuffer,
|
||||||
|
offset,
|
||||||
|
Const(SupportBuffer.Binding),
|
||||||
|
Const((int)SupportBufferField.BufferTextureOffset),
|
||||||
|
Const(stageIndex * SupportBuffer.TextureCount + bindingIndex),
|
||||||
|
Const(isImage ? 1 : 0)));
|
||||||
|
|
||||||
|
node.List.AddBefore(node, new Operation(Instruction.Add, coordPlusOffset, source, offset));
|
||||||
|
|
||||||
|
sources[coordsIndex] = coordPlusOffset;
|
||||||
|
|
||||||
|
TextureOperation newTexOp = new(
|
||||||
|
texOp.Inst,
|
||||||
|
texOp.Type,
|
||||||
|
texOp.Format,
|
||||||
|
texOp.Flags,
|
||||||
|
texOp.Set,
|
||||||
|
texOp.Binding,
|
||||||
|
texOp.Index,
|
||||||
|
dests,
|
||||||
|
sources);
|
||||||
|
|
||||||
|
node = node.List.AddBefore(node, newTexOp);
|
||||||
|
|
||||||
|
Utils.DeleteNode(oldNode, texOp);
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
private static LinkedListNode<INode> InsertConstOffsets(LinkedListNode<INode> node, ResourceManager resourceManager, IGpuAccessor gpuAccessor, ShaderStage stage)
|
private static LinkedListNode<INode> InsertConstOffsets(LinkedListNode<INode> node, ResourceManager resourceManager, IGpuAccessor gpuAccessor, ShaderStage stage)
|
||||||
{
|
{
|
||||||
// Non-constant texture offsets are not allowed (according to the spec),
|
// Non-constant texture offsets are not allowed (according to the spec),
|
||||||
|
|||||||
@@ -784,6 +784,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
supportsGeometryShader: Capabilities.SupportsGeometryShader,
|
supportsGeometryShader: Capabilities.SupportsGeometryShader,
|
||||||
supportsGeometryShaderPassthrough: Capabilities.SupportsGeometryShaderPassthrough,
|
supportsGeometryShaderPassthrough: Capabilities.SupportsGeometryShaderPassthrough,
|
||||||
supportsTransformFeedback: Capabilities.SupportsTransformFeedback,
|
supportsTransformFeedback: Capabilities.SupportsTransformFeedback,
|
||||||
|
supportsImageBufferPixelAlignment: false,
|
||||||
supportsImageLoadFormatted: features2.Features.ShaderStorageImageReadWithoutFormat,
|
supportsImageLoadFormatted: features2.Features.ShaderStorageImageReadWithoutFormat,
|
||||||
supportsLayerVertexTessellation: featuresVk12.ShaderOutputLayer,
|
supportsLayerVertexTessellation: featuresVk12.ShaderOutputLayer,
|
||||||
supportsMismatchingViewFormat: true,
|
supportsMismatchingViewFormat: true,
|
||||||
@@ -797,6 +798,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
supportsShaderNonUniformIndexing:
|
supportsShaderNonUniformIndexing:
|
||||||
featuresVk12.ShaderSampledImageArrayNonUniformIndexing &&
|
featuresVk12.ShaderSampledImageArrayNonUniformIndexing &&
|
||||||
featuresVk12.ShaderStorageImageArrayNonUniformIndexing,
|
featuresVk12.ShaderStorageImageArrayNonUniformIndexing,
|
||||||
|
supportsTextureBufferPixelAlignment: false,
|
||||||
supportsTextureGatherOffsets: features2.Features.ShaderImageGatherExtended,
|
supportsTextureGatherOffsets: features2.Features.ShaderImageGatherExtended,
|
||||||
supportsTextureShadowLod: false,
|
supportsTextureShadowLod: false,
|
||||||
supportsVertexStoreAndAtomics: features2.Features.VertexPipelineStoresAndAtomics,
|
supportsVertexStoreAndAtomics: features2.Features.VertexPipelineStoresAndAtomics,
|
||||||
|
|||||||
Reference in New Issue
Block a user