diff --git a/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs b/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs index d257c193..24b05b90 100644 --- a/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs +++ b/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs @@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache private const ushort FileFormatVersionMajor = 1; private const ushort FileFormatVersionMinor = 2; private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor; - private const uint CodeGenVersion = 3644; + private const uint CodeGenVersion = 3697; private const string SharedTocFileName = "shared.toc"; private const string SharedDataFileName = "shared.data"; diff --git a/Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs b/Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs index 4d20a5ce..c54b79cd 100644 --- a/Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs +++ b/Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs @@ -16,7 +16,7 @@ namespace Ryujinx.Graphics.Shader.Instructions { 0b0111, 0b1011, 0b1101, 0b1110, 0b1111, 0b0000, 0b0000, 0b0000 } }; - private const bool Sample1DAs2D = true; + public const bool Sample1DAs2D = true; private enum TexsType { diff --git a/Ryujinx.Graphics.Shader/IntermediateRepresentation/Operation.cs b/Ryujinx.Graphics.Shader/IntermediateRepresentation/Operation.cs index 955beafd..96132633 100644 --- a/Ryujinx.Graphics.Shader/IntermediateRepresentation/Operation.cs +++ b/Ryujinx.Graphics.Shader/IntermediateRepresentation/Operation.cs @@ -180,6 +180,18 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation _sources[index] = source; } + public void InsertSource(int index, Operand source) + { + Operand[] newSources = new Operand[_sources.Length + 1]; + + Array.Copy(_sources, 0, newSources, 0, index); + Array.Copy(_sources, index, newSources, index + 1, _sources.Length - index); + + newSources[index] = source; + + _sources = newSources; + } + protected void RemoveSource(int index) { SetSource(index, null); diff --git a/Ryujinx.Graphics.Shader/IntermediateRepresentation/TextureOperation.cs b/Ryujinx.Graphics.Shader/IntermediateRepresentation/TextureOperation.cs index ea9ae39c..8cfcb0e9 100644 --- a/Ryujinx.Graphics.Shader/IntermediateRepresentation/TextureOperation.cs +++ b/Ryujinx.Graphics.Shader/IntermediateRepresentation/TextureOperation.cs @@ -60,5 +60,10 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation CbufSlot = cbufSlot; Handle = handle; } + + public void SetLodLevelFlag() + { + Flags |= TextureFlags.LodLevel; + } } } \ No newline at end of file diff --git a/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs b/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs index 73d89761..0c196c4d 100644 --- a/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs +++ b/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs @@ -1,4 +1,5 @@ -using Ryujinx.Graphics.Shader.IntermediateRepresentation; +using Ryujinx.Graphics.Shader.Instructions; +using Ryujinx.Graphics.Shader.IntermediateRepresentation; using System.Collections.Generic; namespace Ryujinx.Graphics.Shader.Translation.Optimizations @@ -30,11 +31,19 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations texOp.Inst == Instruction.TextureSize) { Operand bindlessHandle = Utils.FindLastOperation(texOp.GetSource(0), block); - bool rewriteSamplerType = texOp.Inst == Instruction.TextureSize; + + // Some instructions do not encode an accurate sampler type: + // - Most instructions uses the same type for 1D and Buffer. + // - Query instructions may not have any type. + // For those cases, we need to try getting the type from current GPU state, + // as long bindless elimination is successful and we know where the texture descriptor is located. + bool rewriteSamplerType = + texOp.Type == SamplerType.TextureBuffer || + texOp.Inst == Instruction.TextureSize; if (bindlessHandle.Type == OperandType.ConstantBuffer) { - SetHandle(config, texOp, bindlessHandle.GetCbufOffset(), bindlessHandle.GetCbufSlot(), rewriteSamplerType); + SetHandle(config, texOp, bindlessHandle.GetCbufOffset(), bindlessHandle.GetCbufSlot(), rewriteSamplerType, isImage: false); continue; } @@ -137,7 +146,8 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations texOp, TextureHandle.PackOffsets(src0.GetCbufOffset(), ((src1.Value >> 20) & 0xfff), handleType), TextureHandle.PackSlots(src0.GetCbufSlot(), 0), - rewriteSamplerType); + rewriteSamplerType, + isImage: false); } else if (src1.Type == OperandType.ConstantBuffer) { @@ -146,7 +156,8 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations texOp, TextureHandle.PackOffsets(src0.GetCbufOffset(), src1.GetCbufOffset(), handleType), TextureHandle.PackSlots(src0.GetCbufSlot(), src1.GetCbufSlot()), - rewriteSamplerType); + rewriteSamplerType, + isImage: false); } } else if (texOp.Inst == Instruction.ImageLoad || @@ -172,7 +183,9 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations } } - SetHandle(config, texOp, cbufOffset, cbufSlot, false); + bool rewriteSamplerType = texOp.Type == SamplerType.TextureBuffer; + + SetHandle(config, texOp, cbufOffset, cbufSlot, rewriteSamplerType, isImage: true); } } } @@ -209,13 +222,39 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations return null; } - private static void SetHandle(ShaderConfig config, TextureOperation texOp, int cbufOffset, int cbufSlot, bool rewriteSamplerType) + private static void SetHandle(ShaderConfig config, TextureOperation texOp, int cbufOffset, int cbufSlot, bool rewriteSamplerType, bool isImage) { texOp.SetHandle(cbufOffset, cbufSlot); if (rewriteSamplerType) { - texOp.Type = config.GpuAccessor.QuerySamplerType(cbufOffset, cbufSlot); + SamplerType newType = config.GpuAccessor.QuerySamplerType(cbufOffset, cbufSlot); + + if (texOp.Inst.IsTextureQuery()) + { + texOp.Type = newType; + } + else if (texOp.Type == SamplerType.TextureBuffer && newType == SamplerType.Texture1D) + { + int coordsCount = 1; + + if (InstEmit.Sample1DAs2D) + { + newType = SamplerType.Texture2D; + texOp.InsertSource(coordsCount++, OperandHelper.Const(0)); + } + + if (!isImage && + (texOp.Flags & TextureFlags.IntCoords) != 0 && + (texOp.Flags & TextureFlags.LodLevel) == 0) + { + // IntCoords textures must always have explicit LOD. + texOp.SetLodLevelFlag(); + texOp.InsertSource(coordsCount, OperandHelper.Const(0)); + } + + texOp.Type = newType; + } } config.SetUsedTexture(texOp.Inst, texOp.Type, texOp.Format, texOp.Flags, cbufSlot, cbufOffset);