forked from Mirror/Ryujinx
Support non-constant texture offsets on non-NVIDIA gpus
This commit is contained in:
parent
3323a3a042
commit
f2c85c5d58
11 changed files with 319 additions and 33 deletions
|
@ -3,6 +3,7 @@ namespace Ryujinx.Graphics.GAL
|
||||||
public struct Capabilities
|
public struct Capabilities
|
||||||
{
|
{
|
||||||
public bool SupportsAstcCompression { get; }
|
public bool SupportsAstcCompression { get; }
|
||||||
|
public bool SupportsNonConstantTextureOffset { get; }
|
||||||
|
|
||||||
public int MaximumViewportDimensions { get; }
|
public int MaximumViewportDimensions { get; }
|
||||||
public int MaximumComputeSharedMemorySize { get; }
|
public int MaximumComputeSharedMemorySize { get; }
|
||||||
|
@ -10,11 +11,13 @@ namespace Ryujinx.Graphics.GAL
|
||||||
|
|
||||||
public Capabilities(
|
public Capabilities(
|
||||||
bool supportsAstcCompression,
|
bool supportsAstcCompression,
|
||||||
|
bool supportsNonConstantTextureOffset,
|
||||||
int maximumViewportDimensions,
|
int maximumViewportDimensions,
|
||||||
int maximumComputeSharedMemorySize,
|
int maximumComputeSharedMemorySize,
|
||||||
int storageBufferOffsetAlignment)
|
int storageBufferOffsetAlignment)
|
||||||
{
|
{
|
||||||
SupportsAstcCompression = supportsAstcCompression;
|
SupportsAstcCompression = supportsAstcCompression;
|
||||||
|
SupportsNonConstantTextureOffset = supportsNonConstantTextureOffset;
|
||||||
MaximumViewportDimensions = maximumViewportDimensions;
|
MaximumViewportDimensions = maximumViewportDimensions;
|
||||||
MaximumComputeSharedMemorySize = maximumComputeSharedMemorySize;
|
MaximumComputeSharedMemorySize = maximumComputeSharedMemorySize;
|
||||||
StorageBufferOffsetAlignment = storageBufferOffsetAlignment;
|
StorageBufferOffsetAlignment = storageBufferOffsetAlignment;
|
||||||
|
|
|
@ -355,7 +355,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
return new ShaderCapabilities(
|
return new ShaderCapabilities(
|
||||||
_context.Capabilities.MaximumViewportDimensions,
|
_context.Capabilities.MaximumViewportDimensions,
|
||||||
_context.Capabilities.MaximumComputeSharedMemorySize,
|
_context.Capabilities.MaximumComputeSharedMemorySize,
|
||||||
_context.Capabilities.StorageBufferOffsetAlignment);
|
_context.Capabilities.StorageBufferOffsetAlignment,
|
||||||
|
_context.Capabilities.SupportsNonConstantTextureOffset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -11,7 +11,10 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
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));
|
||||||
|
|
||||||
|
private static Lazy<bool> _isNvidiaDriver = new Lazy<bool>(() => IsNvidiaDriver());
|
||||||
|
|
||||||
public static bool SupportsAstcCompression => _supportsAstcCompression.Value;
|
public static bool SupportsAstcCompression => _supportsAstcCompression.Value;
|
||||||
|
public static bool SupportsNonConstantTextureOffset => _isNvidiaDriver.Value;
|
||||||
|
|
||||||
public static int MaximumViewportDimensions => _maximumViewportDimensions.Value;
|
public static int MaximumViewportDimensions => _maximumViewportDimensions.Value;
|
||||||
public static int MaximumComputeSharedMemorySize => _maximumComputeSharedMemorySize.Value;
|
public static int MaximumComputeSharedMemorySize => _maximumComputeSharedMemorySize.Value;
|
||||||
|
@ -36,5 +39,10 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
{
|
{
|
||||||
return GL.GetInteger((GetPName)name);
|
return GL.GetInteger((GetPName)name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static bool IsNvidiaDriver()
|
||||||
|
{
|
||||||
|
return GL.GetString(StringName.Vendor).Equals("NVIDIA Corporation");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -63,6 +63,7 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
{
|
{
|
||||||
return new Capabilities(
|
return new Capabilities(
|
||||||
HwCapabilities.SupportsAstcCompression,
|
HwCapabilities.SupportsAstcCompression,
|
||||||
|
HwCapabilities.SupportsNonConstantTextureOffset,
|
||||||
HwCapabilities.MaximumViewportDimensions,
|
HwCapabilities.MaximumViewportDimensions,
|
||||||
HwCapabilities.MaximumComputeSharedMemorySize,
|
HwCapabilities.MaximumComputeSharedMemorySize,
|
||||||
HwCapabilities.StorageBufferOffsetAlignment);
|
HwCapabilities.StorageBufferOffsetAlignment);
|
||||||
|
|
|
@ -133,6 +133,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||||
case Instruction.LoadStorage:
|
case Instruction.LoadStorage:
|
||||||
return InstGenMemory.LoadStorage(context, operation);
|
return InstGenMemory.LoadStorage(context, operation);
|
||||||
|
|
||||||
|
case Instruction.Lod:
|
||||||
|
return InstGenMemory.Lod(context, operation);
|
||||||
|
|
||||||
case Instruction.PackHalf2x16:
|
case Instruction.PackHalf2x16:
|
||||||
return InstGenPacking.PackHalf2x16(context, operation);
|
return InstGenPacking.PackHalf2x16(context, operation);
|
||||||
|
|
||||||
|
|
|
@ -73,6 +73,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||||
Add(Instruction.LoadLocal, InstType.Special);
|
Add(Instruction.LoadLocal, InstType.Special);
|
||||||
Add(Instruction.LoadShared, InstType.Special);
|
Add(Instruction.LoadShared, InstType.Special);
|
||||||
Add(Instruction.LoadStorage, InstType.Special);
|
Add(Instruction.LoadStorage, InstType.Special);
|
||||||
|
Add(Instruction.Lod, InstType.Special);
|
||||||
Add(Instruction.LogarithmB2, InstType.CallUnary, "log2");
|
Add(Instruction.LogarithmB2, InstType.CallUnary, "log2");
|
||||||
Add(Instruction.LogicalAnd, InstType.OpBinaryCom, "&&", 9);
|
Add(Instruction.LogicalAnd, InstType.OpBinaryCom, "&&", 9);
|
||||||
Add(Instruction.LogicalExclusiveOr, InstType.OpBinaryCom, "^^", 10);
|
Add(Instruction.LogicalExclusiveOr, InstType.OpBinaryCom, "^^", 10);
|
||||||
|
|
|
@ -148,6 +148,48 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||||
return GetStorageBufferAccessor(indexExpr, offsetExpr, context.Config.Stage);
|
return GetStorageBufferAccessor(indexExpr, offsetExpr, context.Config.Stage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string Lod(CodeGenContext context, AstOperation operation)
|
||||||
|
{
|
||||||
|
AstTextureOperation texOp = (AstTextureOperation)operation;
|
||||||
|
|
||||||
|
int coordsCount = texOp.Type.GetDimensions();
|
||||||
|
|
||||||
|
bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0;
|
||||||
|
|
||||||
|
bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0;
|
||||||
|
|
||||||
|
string indexExpr = null;
|
||||||
|
|
||||||
|
if (isIndexed)
|
||||||
|
{
|
||||||
|
indexExpr = GetSoureExpr(context, texOp.GetSource(0), VariableType.S32);
|
||||||
|
}
|
||||||
|
|
||||||
|
string samplerName = OperandManager.GetSamplerName(context.Config.Stage, texOp, indexExpr);
|
||||||
|
|
||||||
|
int coordsIndex = isBindless || isIndexed ? 1 : 0;
|
||||||
|
|
||||||
|
string coordsExpr;
|
||||||
|
|
||||||
|
if (coordsCount > 1)
|
||||||
|
{
|
||||||
|
string[] elems = new string[coordsCount];
|
||||||
|
|
||||||
|
for (int index = 0; index < coordsCount; index++)
|
||||||
|
{
|
||||||
|
elems[index] = GetSoureExpr(context, texOp.GetSource(coordsIndex + index), VariableType.F32);
|
||||||
|
}
|
||||||
|
|
||||||
|
coordsExpr = "vec" + coordsCount + "(" + string.Join(", ", elems) + ")";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
coordsExpr = GetSoureExpr(context, texOp.GetSource(coordsIndex), VariableType.F32);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $"textureQueryLod({samplerName}, {coordsExpr}){GetMask(texOp.Index)}";
|
||||||
|
}
|
||||||
|
|
||||||
public static string StoreLocal(CodeGenContext context, AstOperation operation)
|
public static string StoreLocal(CodeGenContext context, AstOperation operation)
|
||||||
{
|
{
|
||||||
return StoreLocalOrShared(context, operation, DefaultNames.LocalMemoryName);
|
return StoreLocalOrShared(context, operation, DefaultNames.LocalMemoryName);
|
||||||
|
@ -359,17 +401,17 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hasExtraCompareArg)
|
||||||
|
{
|
||||||
|
Append(Src(VariableType.F32));
|
||||||
|
}
|
||||||
|
|
||||||
if (hasDerivatives)
|
if (hasDerivatives)
|
||||||
{
|
{
|
||||||
Append(AssembleDerivativesVector(coordsCount)); // dPdx
|
Append(AssembleDerivativesVector(coordsCount)); // dPdx
|
||||||
Append(AssembleDerivativesVector(coordsCount)); // dPdy
|
Append(AssembleDerivativesVector(coordsCount)); // dPdy
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasExtraCompareArg)
|
|
||||||
{
|
|
||||||
Append(Src(VariableType.F32));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isMultisample)
|
if (isMultisample)
|
||||||
{
|
{
|
||||||
Append(Src(VariableType.S32));
|
Append(Src(VariableType.S32));
|
||||||
|
@ -446,11 +488,13 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||||
|
|
||||||
string samplerName = OperandManager.GetSamplerName(context.Config.Stage, texOp, indexExpr);
|
string samplerName = OperandManager.GetSamplerName(context.Config.Stage, texOp, indexExpr);
|
||||||
|
|
||||||
IAstNode src0 = operation.GetSource(isBindless || isIndexed ? 1 : 0);
|
int lodSrcIndex = isBindless || isIndexed ? 1 : 0;
|
||||||
|
|
||||||
string src0Expr = GetSoureExpr(context, src0, GetSrcVarType(operation.Inst, 0));
|
IAstNode lod = operation.GetSource(lodSrcIndex);
|
||||||
|
|
||||||
return $"textureSize({samplerName}, {src0Expr}){GetMask(texOp.Index)}";
|
string lodExpr = GetSoureExpr(context, lod, GetSrcVarType(operation.Inst, lodSrcIndex));
|
||||||
|
|
||||||
|
return $"textureSize({samplerName}, {lodExpr}){GetMask(texOp.Index)}";
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GetStorageBufferAccessor(string slotExpr, string offsetExpr, ShaderStage stage)
|
private static string GetStorageBufferAccessor(string slotExpr, string offsetExpr, ShaderStage stage)
|
||||||
|
|
|
@ -71,6 +71,7 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
|
||||||
LoadLocal,
|
LoadLocal,
|
||||||
LoadShared,
|
LoadShared,
|
||||||
LoadStorage,
|
LoadStorage,
|
||||||
|
Lod,
|
||||||
LogarithmB2,
|
LogarithmB2,
|
||||||
LogicalAnd,
|
LogicalAnd,
|
||||||
LogicalExclusiveOr,
|
LogicalExclusiveOr,
|
||||||
|
|
|
@ -3,22 +3,25 @@ namespace Ryujinx.Graphics.Shader
|
||||||
public struct ShaderCapabilities
|
public struct ShaderCapabilities
|
||||||
{
|
{
|
||||||
// Initialize with default values for Maxwell.
|
// Initialize with default values for Maxwell.
|
||||||
private static readonly ShaderCapabilities _default = new ShaderCapabilities(32768, 49152, 16);
|
private static readonly ShaderCapabilities _default = new ShaderCapabilities(0x8000, 0xc000, 16, true);
|
||||||
|
|
||||||
public static ShaderCapabilities Default => _default;
|
public static ShaderCapabilities Default => _default;
|
||||||
|
|
||||||
public int MaximumViewportDimensions { get; }
|
public int MaximumViewportDimensions { get; }
|
||||||
public int MaximumComputeSharedMemorySize { get; }
|
public int MaximumComputeSharedMemorySize { get; }
|
||||||
public int StorageBufferOffsetAlignment { get; }
|
public int StorageBufferOffsetAlignment { get; }
|
||||||
|
public bool SupportsNonConstantTextureOffset { get; }
|
||||||
|
|
||||||
public ShaderCapabilities(
|
public ShaderCapabilities(
|
||||||
int maximumViewportDimensions,
|
int maximumViewportDimensions,
|
||||||
int maximumComputeSharedMemorySize,
|
int maximumComputeSharedMemorySize,
|
||||||
int storageBufferOffsetAlignment)
|
int storageBufferOffsetAlignment,
|
||||||
|
bool supportsNonConstantTextureOffset)
|
||||||
{
|
{
|
||||||
MaximumViewportDimensions = maximumViewportDimensions;
|
MaximumViewportDimensions = maximumViewportDimensions;
|
||||||
MaximumComputeSharedMemorySize = maximumComputeSharedMemorySize;
|
MaximumComputeSharedMemorySize = maximumComputeSharedMemorySize;
|
||||||
StorageBufferOffsetAlignment = storageBufferOffsetAlignment;
|
StorageBufferOffsetAlignment = storageBufferOffsetAlignment;
|
||||||
|
SupportsNonConstantTextureOffset = supportsNonConstantTextureOffset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -85,6 +85,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||||
Add(Instruction.LoadLocal, VariableType.U32, VariableType.S32);
|
Add(Instruction.LoadLocal, VariableType.U32, VariableType.S32);
|
||||||
Add(Instruction.LoadShared, VariableType.U32, VariableType.S32);
|
Add(Instruction.LoadShared, VariableType.U32, VariableType.S32);
|
||||||
Add(Instruction.LoadStorage, VariableType.U32, VariableType.S32, VariableType.S32);
|
Add(Instruction.LoadStorage, VariableType.U32, VariableType.S32, VariableType.S32);
|
||||||
|
Add(Instruction.Lod, VariableType.F32);
|
||||||
Add(Instruction.LogarithmB2, VariableType.Scalar, VariableType.Scalar);
|
Add(Instruction.LogarithmB2, VariableType.Scalar, VariableType.Scalar);
|
||||||
Add(Instruction.LogicalAnd, VariableType.Bool, VariableType.Bool, VariableType.Bool);
|
Add(Instruction.LogicalAnd, VariableType.Bool, VariableType.Bool, VariableType.Bool);
|
||||||
Add(Instruction.LogicalExclusiveOr, VariableType.Bool, VariableType.Bool, VariableType.Bool);
|
Add(Instruction.LogicalExclusiveOr, VariableType.Bool, VariableType.Bool, VariableType.Bool);
|
||||||
|
@ -139,9 +140,11 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||||
{
|
{
|
||||||
// TODO: Return correct type depending on source index,
|
// TODO: Return correct type depending on source index,
|
||||||
// that can improve the decompiler output.
|
// that can improve the decompiler output.
|
||||||
if (inst == Instruction.TextureSample ||
|
if (
|
||||||
inst == Instruction.ImageLoad ||
|
inst == Instruction.ImageLoad ||
|
||||||
inst == Instruction.ImageStore)
|
inst == Instruction.ImageStore ||
|
||||||
|
inst == Instruction.Lod ||
|
||||||
|
inst == Instruction.TextureSample)
|
||||||
{
|
{
|
||||||
return VariableType.F32;
|
return VariableType.F32;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
|
using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
|
||||||
using static Ryujinx.Graphics.Shader.Translation.GlobalMemory;
|
using static Ryujinx.Graphics.Shader.Translation.GlobalMemory;
|
||||||
|
@ -23,13 +24,18 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
|
|
||||||
if (UsesGlobalMemory(operation.Inst))
|
if (UsesGlobalMemory(operation.Inst))
|
||||||
{
|
{
|
||||||
node = LowerGlobal(node, config);
|
node = RewriteGlobalAccess(node, config);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!config.Capabilities.SupportsNonConstantTextureOffset && operation.Inst == Instruction.TextureSample)
|
||||||
|
{
|
||||||
|
node = RewriteTextureSample(node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static LinkedListNode<INode> LowerGlobal(LinkedListNode<INode> node, ShaderConfig config)
|
private static LinkedListNode<INode> RewriteGlobalAccess(LinkedListNode<INode> node, ShaderConfig config)
|
||||||
{
|
{
|
||||||
Operation operation = (Operation)node.Value;
|
Operation operation = (Operation)node.Value;
|
||||||
|
|
||||||
|
@ -117,5 +123,217 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static LinkedListNode<INode> RewriteTextureSample(LinkedListNode<INode> node)
|
||||||
|
{
|
||||||
|
TextureOperation texOp = (TextureOperation)node.Value;
|
||||||
|
|
||||||
|
bool hasOffset = (texOp.Flags & TextureFlags.Offset) != 0;
|
||||||
|
bool hasOffsets = (texOp.Flags & TextureFlags.Offsets) != 0;
|
||||||
|
|
||||||
|
if (!(hasOffset || hasOffsets))
|
||||||
|
{
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0;
|
||||||
|
bool isGather = (texOp.Flags & TextureFlags.Gather) != 0;
|
||||||
|
bool hasDerivatives = (texOp.Flags & TextureFlags.Derivatives) != 0;
|
||||||
|
bool hasLodBias = (texOp.Flags & TextureFlags.LodBias) != 0;
|
||||||
|
bool hasLodLevel = (texOp.Flags & TextureFlags.LodLevel) != 0;
|
||||||
|
|
||||||
|
bool isArray = (texOp.Type & SamplerType.Array) != 0;
|
||||||
|
bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0;
|
||||||
|
bool isMultisample = (texOp.Type & SamplerType.Multisample) != 0;
|
||||||
|
bool isShadow = (texOp.Type & SamplerType.Shadow) != 0;
|
||||||
|
|
||||||
|
int coordsCount = texOp.Type.GetDimensions();
|
||||||
|
|
||||||
|
int offsetsCount = coordsCount * (hasOffsets ? 4 : 1);
|
||||||
|
|
||||||
|
Operand[] offsets = new Operand[offsetsCount];
|
||||||
|
Operand[] sources = new Operand[texOp.SourcesCount - offsetsCount];
|
||||||
|
|
||||||
|
int srcIndex = 0;
|
||||||
|
int dstIndex = 0;
|
||||||
|
|
||||||
|
int copyCount = 0;
|
||||||
|
|
||||||
|
if (isBindless || isIndexed)
|
||||||
|
{
|
||||||
|
copyCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
Operand[] lodSources = new Operand[copyCount + coordsCount];
|
||||||
|
|
||||||
|
for (int index = 0; index < lodSources.Length; index++)
|
||||||
|
{
|
||||||
|
lodSources[index] = texOp.GetSource(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
copyCount += coordsCount;
|
||||||
|
|
||||||
|
if (isArray)
|
||||||
|
{
|
||||||
|
copyCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isShadow)
|
||||||
|
{
|
||||||
|
copyCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasDerivatives)
|
||||||
|
{
|
||||||
|
copyCount += coordsCount * 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isMultisample)
|
||||||
|
{
|
||||||
|
copyCount++;
|
||||||
|
}
|
||||||
|
else if (hasLodLevel)
|
||||||
|
{
|
||||||
|
copyCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int index = 0; index < copyCount; index++)
|
||||||
|
{
|
||||||
|
sources[dstIndex++] = texOp.GetSource(srcIndex++);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool areAllOffsetsConstant = true;
|
||||||
|
|
||||||
|
for (int index = 0; index < offsetsCount; index++)
|
||||||
|
{
|
||||||
|
Operand offset = texOp.GetSource(srcIndex++);
|
||||||
|
|
||||||
|
areAllOffsetsConstant &= offset.Type == OperandType.Constant;
|
||||||
|
|
||||||
|
offsets[index] = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (areAllOffsetsConstant)
|
||||||
|
{
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasLodBias)
|
||||||
|
{
|
||||||
|
sources[dstIndex++] = texOp.GetSource(srcIndex++);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isGather && !isShadow)
|
||||||
|
{
|
||||||
|
sources[dstIndex++] = texOp.GetSource(srcIndex++);
|
||||||
|
}
|
||||||
|
|
||||||
|
Operand Int(Operand value)
|
||||||
|
{
|
||||||
|
Operand res = Local();
|
||||||
|
|
||||||
|
node.List.AddBefore(node, new Operation(Instruction.ConvertFPToS32, res, value));
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
Operand Float(Operand value)
|
||||||
|
{
|
||||||
|
Operand res = Local();
|
||||||
|
|
||||||
|
node.List.AddBefore(node, new Operation(Instruction.ConvertS32ToFP, res, value));
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
Operand lod = Local();
|
||||||
|
|
||||||
|
node.List.AddBefore(node, new TextureOperation(
|
||||||
|
Instruction.Lod,
|
||||||
|
texOp.Type,
|
||||||
|
texOp.Flags,
|
||||||
|
texOp.Handle,
|
||||||
|
1,
|
||||||
|
lod,
|
||||||
|
lodSources));
|
||||||
|
|
||||||
|
int coordsIndex = isBindless || isIndexed ? 1 : 0;
|
||||||
|
|
||||||
|
for (int index = 0; index < coordsCount; index++)
|
||||||
|
{
|
||||||
|
Operand coordSize = Local();
|
||||||
|
|
||||||
|
Operand[] texSizeSources;
|
||||||
|
|
||||||
|
if (isBindless || isIndexed)
|
||||||
|
{
|
||||||
|
texSizeSources = new Operand[] { sources[0], Int(lod) };
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
texSizeSources = new Operand[] { Int(lod) };
|
||||||
|
}
|
||||||
|
|
||||||
|
node.List.AddBefore(node, new TextureOperation(
|
||||||
|
Instruction.TextureSize,
|
||||||
|
texOp.Type,
|
||||||
|
texOp.Flags,
|
||||||
|
texOp.Handle,
|
||||||
|
index,
|
||||||
|
coordSize,
|
||||||
|
texSizeSources));
|
||||||
|
|
||||||
|
Operand offset = Local();
|
||||||
|
|
||||||
|
Operand intOffset = offsets[index + (hasOffsets ? texOp.Index * coordsCount : 0)];
|
||||||
|
|
||||||
|
node.List.AddBefore(node, new Operation(Instruction.FP | Instruction.Divide, offset, Float(intOffset), Float(coordSize)));
|
||||||
|
|
||||||
|
Operand source = sources[coordsIndex + index];
|
||||||
|
|
||||||
|
Operand coordPlusOffset = Local();
|
||||||
|
|
||||||
|
node.List.AddBefore(node, new Operation(Instruction.FP | Instruction.Add, coordPlusOffset, source, offset));
|
||||||
|
|
||||||
|
sources[coordsIndex + index] = coordPlusOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
int componentIndex;
|
||||||
|
|
||||||
|
if (isGather && !isShadow)
|
||||||
|
{
|
||||||
|
Operand gatherComponent = sources[dstIndex - 1];
|
||||||
|
|
||||||
|
Debug.Assert(gatherComponent.Type == OperandType.Constant);
|
||||||
|
|
||||||
|
componentIndex = gatherComponent.Value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
componentIndex = texOp.Index;
|
||||||
|
}
|
||||||
|
|
||||||
|
TextureOperation newTexOp = new TextureOperation(
|
||||||
|
Instruction.TextureSample,
|
||||||
|
texOp.Type,
|
||||||
|
texOp.Flags & ~(TextureFlags.Offset | TextureFlags.Offsets),
|
||||||
|
texOp.Handle,
|
||||||
|
componentIndex,
|
||||||
|
texOp.Dest,
|
||||||
|
sources);
|
||||||
|
|
||||||
|
for (int index = 0; index < texOp.SourcesCount; index++)
|
||||||
|
{
|
||||||
|
texOp.SetSource(index, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
LinkedListNode<INode> oldNode = node;
|
||||||
|
|
||||||
|
node = node.List.AddBefore(node, newTexOp);
|
||||||
|
|
||||||
|
node.List.Remove(oldNode);
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Reference in a new issue