aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/Compute.cs39
-rw-r--r--Ryujinx.Graphics.Gpu/Image/TextureManager.cs11
-rw-r--r--Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs151
-rw-r--r--Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs19
-rw-r--r--Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGen.cs36
-rw-r--r--Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs54
-rw-r--r--Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs6
-rw-r--r--Ryujinx.Graphics.Shader/Decoders/OpCodeTable.cs1
-rw-r--r--Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs262
-rw-r--r--Ryujinx.Graphics.Shader/IntermediateRepresentation/TextureOperation.cs2
-rw-r--r--Ryujinx.Graphics.Shader/QueryInfoName.cs3
-rw-r--r--Ryujinx.Graphics.Shader/StructuredIr/AstTextureOperation.cs7
-rw-r--r--Ryujinx.Graphics.Shader/StructuredIr/StructuredProgram.cs6
-rw-r--r--Ryujinx.Graphics.Shader/TextureFormat.cs128
-rw-r--r--Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs2
15 files changed, 619 insertions, 108 deletions
diff --git a/Ryujinx.Graphics.Gpu/Engine/Compute.cs b/Ryujinx.Graphics.Gpu/Engine/Compute.cs
index fc257f99..920cf0dd 100644
--- a/Ryujinx.Graphics.Gpu/Engine/Compute.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Compute.cs
@@ -29,7 +29,26 @@ namespace Ryujinx.Graphics.Gpu.Engine
int sharedMemorySize = Math.Min(qmd.SharedMemorySize, _context.Capabilities.MaximumComputeSharedMemorySize);
+ uint sbEnableMask = 0;
+ uint ubEnableMask = 0;
+
+ for (int index = 0; index < Constants.TotalCpUniformBuffers; index++)
+ {
+ if (!qmd.ConstantBufferValid(index))
+ {
+ continue;
+ }
+
+ ubEnableMask |= 1u << index;
+
+ ulong gpuVa = (uint)qmd.ConstantBufferAddrLower(index) | (ulong)qmd.ConstantBufferAddrUpper(index) << 32;
+ ulong size = (ulong)qmd.ConstantBufferSize(index);
+
+ BufferManager.SetComputeUniformBuffer(index, gpuVa, size);
+ }
+
ComputeShader cs = ShaderCache.GetComputeShader(
+ state,
shaderGpuVa,
qmd.CtaThreadDimension0,
qmd.CtaThreadDimension1,
@@ -49,25 +68,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
TextureManager.SetComputeTextureBufferIndex(state.Get<int>(MethodOffset.TextureBufferIndex));
- ShaderProgramInfo info = cs.Shader.Program.Info;
-
- uint sbEnableMask = 0;
- uint ubEnableMask = 0;
-
- for (int index = 0; index < Constants.TotalCpUniformBuffers; index++)
- {
- if (!qmd.ConstantBufferValid(index))
- {
- continue;
- }
-
- ubEnableMask |= 1u << index;
-
- ulong gpuVa = (uint)qmd.ConstantBufferAddrLower(index) | (ulong)qmd.ConstantBufferAddrUpper(index) << 32;
- ulong size = (ulong)qmd.ConstantBufferSize(index);
-
- BufferManager.SetComputeUniformBuffer(index, gpuVa, size);
- }
+ ShaderProgramInfo info = cs.Shader.Program.Info;
for (int index = 0; index < info.CBuffers.Count; index++)
{
diff --git a/Ryujinx.Graphics.Gpu/Image/TextureManager.cs b/Ryujinx.Graphics.Gpu/Image/TextureManager.cs
index 27cbc6ff..b127690b 100644
--- a/Ryujinx.Graphics.Gpu/Image/TextureManager.cs
+++ b/Ryujinx.Graphics.Gpu/Image/TextureManager.cs
@@ -208,6 +208,17 @@ namespace Ryujinx.Graphics.Gpu.Image
}
/// <summary>
+ /// Gets a texture descriptor used on the compute pipeline.
+ /// </summary>
+ /// <param name="state">Current GPU state</param>
+ /// <param name="handle">Shader "fake" handle of the texture</param>
+ /// <returns>The texture descriptor</returns>
+ public TextureDescriptor GetComputeTextureDescriptor(GpuState state, int handle)
+ {
+ return _cpBindingsManager.GetTextureDescriptor(state, 0, handle);
+ }
+
+ /// <summary>
/// Gets a texture descriptor used on the graphics pipeline.
/// </summary>
/// <param name="state">Current GPU state</param>
diff --git a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
index 7ad00f32..6bbc3b11 100644
--- a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
+++ b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
@@ -50,6 +50,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// <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="gpuVa">GPU virtual address of the binary shader code</param>
/// <param name="localSizeX">Local group size X of the computer shader</param>
/// <param name="localSizeY">Local group size Y of the computer shader</param>
@@ -58,6 +59,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// <param name="sharedMemorySize">Shared memory size of the compute shader</param>
/// <returns>Compiled compute shader code</returns>
public ComputeShader GetComputeShader(
+ GpuState state,
ulong gpuVa,
int localSizeX,
int localSizeY,
@@ -79,6 +81,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
}
CachedShader shader = TranslateComputeShader(
+ state,
gpuVa,
localSizeX,
localSizeY,
@@ -241,6 +244,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// <summary>
/// Translates the binary Maxwell shader code to something that the host API accepts.
/// </summary>
+ /// <param name="state">Current GPU state</param>
/// <param name="gpuVa">GPU virtual address of the binary shader code</param>
/// <param name="localSizeX">Local group size X of the computer shader</param>
/// <param name="localSizeY">Local group size Y of the computer shader</param>
@@ -249,6 +253,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// <param name="sharedMemorySize">Shared memory size of the compute shader</param>
/// <returns>Compiled compute shader code</returns>
private CachedShader TranslateComputeShader(
+ GpuState state,
ulong gpuVa,
int localSizeX,
int localSizeY,
@@ -265,12 +270,20 @@ namespace Ryujinx.Graphics.Gpu.Shader
{
return info switch
{
- QueryInfoName.ComputeLocalSizeX => localSizeX,
- QueryInfoName.ComputeLocalSizeY => localSizeY,
- QueryInfoName.ComputeLocalSizeZ => localSizeZ,
- QueryInfoName.ComputeLocalMemorySize => localMemorySize,
- QueryInfoName.ComputeSharedMemorySize => sharedMemorySize,
- _ => QueryInfoCommon(info)
+ QueryInfoName.ComputeLocalSizeX
+ => localSizeX,
+ QueryInfoName.ComputeLocalSizeY
+ => localSizeY,
+ QueryInfoName.ComputeLocalSizeZ
+ => localSizeZ,
+ QueryInfoName.ComputeLocalMemorySize
+ => localMemorySize,
+ QueryInfoName.ComputeSharedMemorySize
+ => sharedMemorySize,
+ QueryInfoName.TextureFormat
+ => (int)QueryComputeTextureFormat(state, index),
+ _
+ => QueryInfoCommon(info)
};
}
@@ -317,10 +330,16 @@ namespace Ryujinx.Graphics.Gpu.Shader
{
return info switch
{
- QueryInfoName.IsTextureBuffer => Convert.ToInt32(QueryIsTextureBuffer(state, (int)stage - 1, index)),
- QueryInfoName.IsTextureRectangle => Convert.ToInt32(QueryIsTextureRectangle(state, (int)stage - 1, index)),
- QueryInfoName.PrimitiveTopology => (int)GetPrimitiveTopology(),
- _ => QueryInfoCommon(info)
+ QueryInfoName.IsTextureBuffer
+ => Convert.ToInt32(QueryIsTextureBuffer(state, (int)stage - 1, index)),
+ QueryInfoName.IsTextureRectangle
+ => Convert.ToInt32(QueryIsTextureRectangle(state, (int)stage - 1, index)),
+ QueryInfoName.PrimitiveTopology
+ => (int)QueryPrimitiveTopology(),
+ QueryInfoName.TextureFormat
+ => (int)QueryGraphicsTextureFormat(state, (int)stage - 1, index),
+ _
+ => QueryInfoCommon(info)
};
}
@@ -378,7 +397,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// This is required by geometry shaders.
/// </summary>
/// <returns>Primitive topology</returns>
- private InputTopology GetPrimitiveTopology()
+ private InputTopology QueryPrimitiveTopology()
{
switch (_context.Methods.PrimitiveType)
{
@@ -414,7 +433,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// <returns>True if the texture is a buffer texture, false otherwise</returns>
private bool QueryIsTextureBuffer(GpuState state, int stageIndex, int index)
{
- return GetTextureDescriptor(state, stageIndex, index).UnpackTextureTarget() == TextureTarget.TextureBuffer;
+ return GetGraphicsTextureDescriptor(state, stageIndex, index).UnpackTextureTarget() == TextureTarget.TextureBuffer;
}
/// <summary>
@@ -428,7 +447,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// <returns>True if the texture is a rectangle texture, false otherwise</returns>
private bool QueryIsTextureRectangle(GpuState state, int stageIndex, int index)
{
- var descriptor = GetTextureDescriptor(state, stageIndex, index);
+ var descriptor = GetGraphicsTextureDescriptor(state, stageIndex, index);
TextureTarget target = descriptor.UnpackTextureTarget();
@@ -439,15 +458,106 @@ namespace Ryujinx.Graphics.Gpu.Shader
}
/// <summary>
- /// Gets the texture descriptor for a given texture on the pool.
+ /// Queries the format of a given texture.
+ /// </summary>
+ /// <param name="state">Current GPU state</param>
+ /// <param name="index">Index of the texture (this is the shader "fake" handle)</param>
+ /// <returns>The texture format</returns>
+ private TextureFormat QueryComputeTextureFormat(GpuState state, int index)
+ {
+ return QueryTextureFormat(GetComputeTextureDescriptor(state, index));
+ }
+
+ /// <summary>
+ /// Queries the format of a given texture.
/// </summary>
/// <param name="state">Current GPU state</param>
/// <param name="stageIndex">Index of the shader stage</param>
/// <param name="index">Index of the texture (this is the shader "fake" handle)</param>
+ /// <returns>The texture format</returns>
+ private TextureFormat QueryGraphicsTextureFormat(GpuState state, int stageIndex, int index)
+ {
+ return QueryTextureFormat(GetGraphicsTextureDescriptor(state, stageIndex, index));
+ }
+
+ /// <summary>
+ /// Queries the format of a given texture.
+ /// </summary>
+ /// <param name="descriptor">Descriptor of the texture from the texture pool</param>
+ /// <returns>The texture format</returns>
+ private static TextureFormat QueryTextureFormat(TextureDescriptor descriptor)
+ {
+ if (!FormatTable.TryGetTextureFormat(descriptor.UnpackFormat(), descriptor.UnpackSrgb(), out FormatInfo formatInfo))
+ {
+ return TextureFormat.Unknown;
+ }
+
+ return formatInfo.Format switch
+ {
+ Format.R8Unorm => TextureFormat.R8Unorm,
+ Format.R8Snorm => TextureFormat.R8Snorm,
+ Format.R8Uint => TextureFormat.R8Uint,
+ Format.R8Sint => TextureFormat.R8Sint,
+ Format.R16Float => TextureFormat.R16Float,
+ Format.R16Unorm => TextureFormat.R16Unorm,
+ Format.R16Snorm => TextureFormat.R16Snorm,
+ Format.R16Uint => TextureFormat.R16Uint,
+ Format.R16Sint => TextureFormat.R16Sint,
+ Format.R32Float => TextureFormat.R32Float,
+ Format.R32Uint => TextureFormat.R32Uint,
+ Format.R32Sint => TextureFormat.R32Sint,
+ Format.R8G8Unorm => TextureFormat.R8G8Unorm,
+ Format.R8G8Snorm => TextureFormat.R8G8Snorm,
+ Format.R8G8Uint => TextureFormat.R8G8Uint,
+ Format.R8G8Sint => TextureFormat.R8G8Sint,
+ Format.R16G16Float => TextureFormat.R16G16Float,
+ Format.R16G16Unorm => TextureFormat.R16G16Unorm,
+ Format.R16G16Snorm => TextureFormat.R16G16Snorm,
+ Format.R16G16Uint => TextureFormat.R16G16Uint,
+ Format.R16G16Sint => TextureFormat.R16G16Sint,
+ Format.R32G32Float => TextureFormat.R32G32Float,
+ Format.R32G32Uint => TextureFormat.R32G32Uint,
+ Format.R32G32Sint => TextureFormat.R32G32Sint,
+ Format.R8G8B8A8Unorm => TextureFormat.R8G8B8A8Unorm,
+ Format.R8G8B8A8Snorm => TextureFormat.R8G8B8A8Snorm,
+ Format.R8G8B8A8Uint => TextureFormat.R8G8B8A8Uint,
+ Format.R8G8B8A8Sint => TextureFormat.R8G8B8A8Sint,
+ Format.R16G16B16A16Float => TextureFormat.R16G16B16A16Float,
+ Format.R16G16B16A16Unorm => TextureFormat.R16G16B16A16Unorm,
+ Format.R16G16B16A16Snorm => TextureFormat.R16G16B16A16Snorm,
+ Format.R16G16B16A16Uint => TextureFormat.R16G16B16A16Uint,
+ Format.R16G16B16A16Sint => TextureFormat.R16G16B16A16Sint,
+ Format.R32G32B32A32Float => TextureFormat.R32G32B32A32Float,
+ Format.R32G32B32A32Uint => TextureFormat.R32G32B32A32Uint,
+ Format.R32G32B32A32Sint => TextureFormat.R32G32B32A32Sint,
+ Format.R10G10B10A2Unorm => TextureFormat.R10G10B10A2Unorm,
+ Format.R10G10B10A2Uint => TextureFormat.R10G10B10A2Uint,
+ Format.R11G11B10Float => TextureFormat.R11G11B10Float,
+ _ => TextureFormat.Unknown
+ };
+ }
+
+ /// <summary>
+ /// Gets the texture descriptor for a given texture on the pool.
+ /// </summary>
+ /// <param name="state">Current GPU state</param>
+ /// <param name="handle">Index of the texture (this is the shader "fake" handle)</param>
+ /// <returns>Texture descriptor</returns>
+ private TextureDescriptor GetComputeTextureDescriptor(GpuState state, int handle)
+ {
+ return _context.Methods.TextureManager.GetComputeTextureDescriptor(state, handle);
+ }
+
+ /// <summary>
+ /// Gets the texture descriptor for a given texture on the pool.
+ /// </summary>
+ /// <param name="state">Current GPU state</param>
+ /// <param name="stageIndex">Index of the shader stage</param>
+ /// <param name="handle">Index of the texture (this is the shader "fake" handle)</param>
/// <returns>Texture descriptor</returns>
- private TextureDescriptor GetTextureDescriptor(GpuState state, int stageIndex, int index)
+ private TextureDescriptor GetGraphicsTextureDescriptor(GpuState state, int stageIndex, int handle)
{
- return _context.Methods.TextureManager.GetGraphicsTextureDescriptor(state, stageIndex, index);
+ return _context.Methods.TextureManager.GetGraphicsTextureDescriptor(state, stageIndex, handle);
}
/// <summary>
@@ -459,9 +569,12 @@ namespace Ryujinx.Graphics.Gpu.Shader
{
return info switch
{
- QueryInfoName.StorageBufferOffsetAlignment => _context.Capabilities.StorageBufferOffsetAlignment,
- QueryInfoName.SupportsNonConstantTextureOffset => Convert.ToInt32(_context.Capabilities.SupportsNonConstantTextureOffset),
- _ => 0
+ QueryInfoName.StorageBufferOffsetAlignment
+ => _context.Capabilities.StorageBufferOffsetAlignment,
+ QueryInfoName.SupportsNonConstantTextureOffset
+ => Convert.ToInt32(_context.Capabilities.SupportsNonConstantTextureOffset),
+ _
+ => 0
};
}
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs
index b1291906..36aff3fc 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs
@@ -326,9 +326,16 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
continue;
}
- string imageTypeName = GetImageTypeName(texOp.Type);
+ string layout = texOp.Format.ToGlslFormat();
- context.AppendLine("writeonly uniform " + imageTypeName + " " + imageName + ";");
+ if (!string.IsNullOrEmpty(layout))
+ {
+ layout = "layout(" + layout + ") ";
+ }
+
+ string imageTypeName = GetImageTypeName(texOp.Type, texOp.Format.GetComponentType());
+
+ context.AppendLine("uniform " + layout + imageTypeName + " " + imageName + ";");
}
foreach (KeyValuePair<string, AstTextureOperation> kv in images)
@@ -455,7 +462,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
return typeName;
}
- private static string GetImageTypeName(SamplerType type)
+ private static string GetImageTypeName(SamplerType type, VariableType componentType)
{
string typeName;
@@ -480,6 +487,12 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
typeName += "Array";
}
+ switch (componentType)
+ {
+ case VariableType.U32: typeName = 'u' + typeName; break;
+ case VariableType.S32: typeName = 'i' + typeName; break;
+ }
+
return typeName;
}
}
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGen.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGen.cs
index fe982770..f1537c3d 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGen.cs
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGen.cs
@@ -4,6 +4,7 @@ using System;
using static Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions.InstGenHelper;
using static Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions.InstGenMemory;
+using static Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions.InstGenPacking;
using static Ryujinx.Graphics.Shader.StructuredIr.InstructionInfo;
namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
@@ -115,53 +116,56 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
{
switch (inst)
{
+ case Instruction.ImageLoad:
+ return ImageLoadOrStore(context, operation);
+
case Instruction.ImageStore:
- return InstGenMemory.ImageStore(context, operation);
+ return ImageLoadOrStore(context, operation);
case Instruction.LoadAttribute:
- return InstGenMemory.LoadAttribute(context, operation);
+ return LoadAttribute(context, operation);
case Instruction.LoadConstant:
- return InstGenMemory.LoadConstant(context, operation);
+ return LoadConstant(context, operation);
case Instruction.LoadLocal:
- return InstGenMemory.LoadLocal(context, operation);
+ return LoadLocal(context, operation);
case Instruction.LoadShared:
- return InstGenMemory.LoadShared(context, operation);
+ return LoadShared(context, operation);
case Instruction.LoadStorage:
- return InstGenMemory.LoadStorage(context, operation);
+ return LoadStorage(context, operation);
case Instruction.Lod:
- return InstGenMemory.Lod(context, operation);
+ return Lod(context, operation);
case Instruction.PackDouble2x32:
- return InstGenPacking.PackDouble2x32(context, operation);
+ return PackDouble2x32(context, operation);
case Instruction.PackHalf2x16:
- return InstGenPacking.PackHalf2x16(context, operation);
+ return PackHalf2x16(context, operation);
case Instruction.StoreLocal:
- return InstGenMemory.StoreLocal(context, operation);
+ return StoreLocal(context, operation);
case Instruction.StoreShared:
- return InstGenMemory.StoreShared(context, operation);
+ return StoreShared(context, operation);
case Instruction.StoreStorage:
- return InstGenMemory.StoreStorage(context, operation);
+ return StoreStorage(context, operation);
case Instruction.TextureSample:
- return InstGenMemory.TextureSample(context, operation);
+ return TextureSample(context, operation);
case Instruction.TextureSize:
- return InstGenMemory.TextureSize(context, operation);
+ return TextureSize(context, operation);
case Instruction.UnpackDouble2x32:
- return InstGenPacking.UnpackDouble2x32(context, operation);
+ return UnpackDouble2x32(context, operation);
case Instruction.UnpackHalf2x16:
- return InstGenPacking.UnpackHalf2x16(context, operation);
+ return UnpackHalf2x16(context, operation);
}
}
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs
index 74828702..d05c77df 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs
@@ -9,16 +9,16 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
{
static class InstGenMemory
{
- public static string ImageStore(CodeGenContext context, AstOperation operation)
+ public static string ImageLoadOrStore(CodeGenContext context, AstOperation operation)
{
AstTextureOperation texOp = (AstTextureOperation)operation;
bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0;
- bool isArray = (texOp.Type & SamplerType.Array) != 0;
+ bool isArray = (texOp.Type & SamplerType.Array) != 0;
bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0;
- string texCall = "imageStore";
+ string texCall = texOp.Inst == Instruction.ImageLoad ? "imageLoad" : "imageStore";
int srcIndex = isBindless ? 1 : 0;
@@ -40,14 +40,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
int coordsCount = texOp.Type.GetDimensions();
- int pCount = coordsCount;
-
- int arrayIndexElem = -1;
-
- if (isArray)
- {
- arrayIndexElem = pCount++;
- }
+ int pCount = coordsCount + (isArray ? 1 : 0);
void Append(string str)
{
@@ -70,23 +63,40 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
Append(Src(VariableType.S32));
}
- string[] cElems = new string[4];
-
- for (int index = 0; index < 4; index++)
+ if (texOp.Inst == Instruction.ImageStore)
{
- if (srcIndex < texOp.SourcesCount)
+ VariableType type = texOp.Format.GetComponentType();
+
+ string[] cElems = new string[4];
+
+ for (int index = 0; index < 4; index++)
{
- cElems[index] = Src(VariableType.F32);
+ if (srcIndex < texOp.SourcesCount)
+ {
+ cElems[index] = Src(type);
+ }
+ else
+ {
+ cElems[index] = type switch
+ {
+ VariableType.S32 => NumberFormatter.FormatInt(0),
+ VariableType.U32 => NumberFormatter.FormatUint(0),
+ _ => NumberFormatter.FormatFloat(0)
+ };
+ }
}
- else
+
+ string prefix = type switch
{
- cElems[index] = NumberFormatter.FormatFloat(0);
- }
- }
+ VariableType.S32 => "i",
+ VariableType.U32 => "u",
+ _ => string.Empty
+ };
- Append("vec4(" + string.Join(", ", cElems) + ")");
+ Append(prefix + "vec4(" + string.Join(", ", cElems) + ")");
+ }
- texCall += ")";
+ texCall += ")" + (texOp.Inst == Instruction.ImageLoad ? GetMask(texOp.Index) : "");
return texCall;
}
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs
index 8d092d4e..e9a37d87 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs
@@ -280,6 +280,12 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
{
return GetOperandVarType((AstOperand)operation.GetSource(0));
}
+ else if (operation is AstTextureOperation texOp &&
+ (texOp.Inst == Instruction.ImageLoad ||
+ texOp.Inst == Instruction.ImageStore))
+ {
+ return texOp.Format.GetComponentType();
+ }
return GetDestVarType(operation.Inst);
}
diff --git a/Ryujinx.Graphics.Shader/Decoders/OpCodeTable.cs b/Ryujinx.Graphics.Shader/Decoders/OpCodeTable.cs
index 2f46ee32..02a8be01 100644
--- a/Ryujinx.Graphics.Shader/Decoders/OpCodeTable.cs
+++ b/Ryujinx.Graphics.Shader/Decoders/OpCodeTable.cs
@@ -219,6 +219,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
Set("1110111101010x", InstEmit.St, typeof(OpCodeMemory));
Set("1110111011011x", InstEmit.Stg, typeof(OpCodeMemory));
Set("1110111101011x", InstEmit.Sts, typeof(OpCodeMemory));
+ Set("11101011000xxx", InstEmit.Suld, typeof(OpCodeImage));
Set("11101011001xxx", InstEmit.Sust, typeof(OpCodeImage));
Set("1111000011111x", InstEmit.Sync, typeof(OpCodeBranchPop));
Set("110000xxxx111x", InstEmit.Tex, typeof(OpCodeTex));
diff --git a/Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs b/Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs
index 7b9794ea..0ff2740b 100644
--- a/Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs
+++ b/Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs
@@ -4,12 +4,152 @@ using Ryujinx.Graphics.Shader.Translation;
using System;
using System.Collections.Generic;
+using static Ryujinx.Graphics.Shader.Instructions.InstEmitHelper;
using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
namespace Ryujinx.Graphics.Shader.Instructions
{
static partial class InstEmit
{
+ public static void Suld(EmitterContext context)
+ {
+ OpCodeImage op = (OpCodeImage)context.CurrOp;
+
+ SamplerType type = ConvertSamplerType(op.Dimensions);
+
+ if (type == SamplerType.None)
+ {
+ context.Config.PrintLog("Invalid image store sampler type.");
+
+ return;
+ }
+
+ // Rb is Rd on the SULD instruction.
+ int rdIndex = op.Rb.Index;
+ int raIndex = op.Ra.Index;
+
+ Operand Ra()
+ {
+ if (raIndex > RegisterConsts.RegisterZeroIndex)
+ {
+ return Const(0);
+ }
+
+ return context.Copy(Register(raIndex++, RegisterType.Gpr));
+ }
+
+ bool isArray = op.Dimensions == ImageDimensions.Image1DArray ||
+ op.Dimensions == ImageDimensions.Image2DArray;
+
+ Operand arrayIndex = isArray ? Ra() : null;
+
+ List<Operand> sourcesList = new List<Operand>();
+
+ if (op.IsBindless)
+ {
+ sourcesList.Add(context.Copy(Register(op.Rc)));
+ }
+
+ int coordsCount = type.GetDimensions();
+
+ for (int index = 0; index < coordsCount; index++)
+ {
+ sourcesList.Add(Ra());
+ }
+
+ if (isArray)
+ {
+ sourcesList.Add(arrayIndex);
+
+ type |= SamplerType.Array;
+ }
+
+ Operand[] sources = sourcesList.ToArray();
+
+ int handle = !op.IsBindless ? op.Immediate : 0;
+
+ TextureFlags flags = op.IsBindless ? TextureFlags.Bindless : TextureFlags.None;
+
+ if (op.UseComponents)
+ {
+ int componentMask = (int)op.Components;
+
+ for (int compMask = componentMask, compIndex = 0; compMask != 0; compMask >>= 1, compIndex++)
+ {
+ if ((compMask & 1) == 0)
+ {
+ continue;
+ }
+
+ if (rdIndex == RegisterConsts.RegisterZeroIndex)
+ {
+ break;
+ }
+
+ Operand rd = Register(rdIndex++, RegisterType.Gpr);
+
+ TextureOperation operation = new TextureOperation(
+ Instruction.ImageLoad,
+ type,
+ flags,
+ handle,
+ compIndex,
+ rd,
+ sources);
+
+ if (!op.IsBindless)
+ {
+ operation.Format = GetTextureFormat(context, handle);
+ }
+
+ context.Add(operation);
+ }
+ }
+ else
+ {
+ if (op.ByteAddress)
+ {
+ int xIndex = op.IsBindless ? 1 : 0;
+
+ sources[xIndex] = context.ShiftRightS32(sources[xIndex], Const(GetComponentSizeInBytesLog2(op.Size)));
+ }
+
+ int components = GetComponents(op.Size);
+
+ for (int compIndex = 0; compIndex < components; compIndex++)
+ {
+ if (rdIndex == RegisterConsts.RegisterZeroIndex)
+ {
+ break;
+ }
+
+ Operand rd = Register(rdIndex++, RegisterType.Gpr);
+
+ TextureOperation operation = new TextureOperation(
+ Instruction.ImageLoad,
+ type,
+ flags,
+ handle,
+ compIndex,
+ rd,
+ sources)
+ {
+ Format = GetTextureFormat(op.Size)
+ };
+
+ context.Add(operation);
+
+ switch (op.Size)
+ {
+ case IntegerSize.U8: context.Copy(rd, ZeroExtendTo32(context, rd, 8)); break;
+ case IntegerSize.U16: context.Copy(rd, ZeroExtendTo32(context, rd, 16)); break;
+ case IntegerSize.S8: context.Copy(rd, SignExtendTo32(context, rd, 8)); break;
+ case IntegerSize.S16: context.Copy(rd, SignExtendTo32(context, rd, 16)); break;
+ }
+ }
+ }
+ }
+
public static void Sust(EmitterContext context)
{
OpCodeImage op = (OpCodeImage)context.CurrOp;
@@ -72,6 +212,8 @@ namespace Ryujinx.Graphics.Shader.Instructions
type |= SamplerType.Array;
}
+ TextureFormat format = TextureFormat.Unknown;
+
if (op.UseComponents)
{
int componentMask = (int)op.Components;
@@ -83,12 +225,33 @@ namespace Ryujinx.Graphics.Shader.Instructions
sourcesList.Add(Rb());
}
}
+
+ if (!op.IsBindless)
+ {
+ format = GetTextureFormat(context, op.Immediate);
+ }
}
else
{
- context.Config.PrintLog("Unsized image store not supported.");
+ if (op.ByteAddress)
+ {
+ int xIndex = op.IsBindless ? 1 : 0;
+
+ sourcesList[xIndex] = context.ShiftRightS32(sourcesList[xIndex], Const(GetComponentSizeInBytesLog2(op.Size)));
+ }
+
+ int components = GetComponents(op.Size);
+
+ for (int compIndex = 0; compIndex < components; compIndex++)
+ {
+ sourcesList.Add(Rb());
+ }
+
+ format = GetTextureFormat(op.Size);
}
+ System.Console.WriteLine(format.ToString());
+
Operand[] sources = sourcesList.ToArray();
int handle = !op.IsBindless ? op.Immediate : 0;
@@ -102,7 +265,10 @@ namespace Ryujinx.Graphics.Shader.Instructions
handle,
0,
null,
- sources);
+ sources)
+ {
+ Format = format
+ };
context.Add(operation);
}
@@ -880,43 +1046,87 @@ namespace Ryujinx.Graphics.Shader.Instructions
}
}
- private static SamplerType ConvertSamplerType(ImageDimensions target)
+ private static int GetComponents(IntegerSize size)
{
- switch (target)
+ return size switch
{
- case ImageDimensions.Image1D:
- return SamplerType.Texture1D;
-
- case ImageDimensions.ImageBuffer:
- return SamplerType.TextureBuffer;
+ IntegerSize.B64 => 2,
+ IntegerSize.B128 => 4,
+ IntegerSize.UB128 => 4,
+ _ => 1
+ };
+ }
- case ImageDimensions.Image1DArray:
- return SamplerType.Texture1D | SamplerType.Array;
+ private static int GetComponentSizeInBytesLog2(IntegerSize size)
+ {
+ return size switch
+ {
+ IntegerSize.U8 => 0,
+ IntegerSize.S8 => 0,
+ IntegerSize.U16 => 1,
+ IntegerSize.S16 => 1,
+ IntegerSize.B32 => 2,
+ IntegerSize.B64 => 3,
+ IntegerSize.B128 => 4,
+ IntegerSize.UB128 => 4,
+ _ => 2
+ };
+ }
- case ImageDimensions.Image2D:
- return SamplerType.Texture2D;
+ private static TextureFormat GetTextureFormat(EmitterContext context, int handle)
+ {
+ var format = (TextureFormat)context.Config.QueryInfo(QueryInfoName.TextureFormat, handle);
- case ImageDimensions.Image2DArray:
- return SamplerType.Texture2D | SamplerType.Array;
+ if (format == TextureFormat.Unknown)
+ {
+ context.Config.PrintLog($"Unknown format for texture {handle}.");
- case ImageDimensions.Image3D:
- return SamplerType.Texture3D;
+ format = TextureFormat.R8G8B8A8Unorm;
}
- return SamplerType.None;
+ return format;
}
- private static SamplerType ConvertSamplerType(TextureDimensions dimensions)
+ private static TextureFormat GetTextureFormat(IntegerSize size)
{
- switch (dimensions)
+ return size switch
{
- case TextureDimensions.Texture1D: return SamplerType.Texture1D;
- case TextureDimensions.Texture2D: return SamplerType.Texture2D;
- case TextureDimensions.Texture3D: return SamplerType.Texture3D;
- case TextureDimensions.TextureCube: return SamplerType.TextureCube;
- }
+ IntegerSize.U8 => TextureFormat.R8Uint,
+ IntegerSize.S8 => TextureFormat.R8Sint,
+ IntegerSize.U16 => TextureFormat.R16Uint,
+ IntegerSize.S16 => TextureFormat.R16Sint,
+ IntegerSize.B32 => TextureFormat.R32Uint,
+ IntegerSize.B64 => TextureFormat.R32G32Uint,
+ IntegerSize.B128 => TextureFormat.R32G32B32A32Uint,
+ IntegerSize.UB128 => TextureFormat.R32G32B32A32Uint,
+ _ => TextureFormat.R32Uint
+ };
+ }
- throw new ArgumentException($"Invalid texture dimensions \"{dimensions}\".");
+ private static SamplerType ConvertSamplerType(ImageDimensions target)
+ {
+ return target switch
+ {
+ ImageDimensions.Image1D => SamplerType.Texture1D,
+ ImageDimensions.ImageBuffer => SamplerType.TextureBuffer,
+ ImageDimensions.Image1DArray => SamplerType.Texture1D | SamplerType.Array,
+ ImageDimensions.Image2D => SamplerType.Texture2D,
+ ImageDimensions.Image2DArray => SamplerType.Texture2D | SamplerType.Array,
+ ImageDimensions.Image3D => SamplerType.Texture3D,
+ _ => SamplerType.None
+ };
+ }
+
+ private static SamplerType ConvertSamplerType(TextureDimensions dimensions)
+ {
+ return dimensions switch
+ {
+ TextureDimensions.Texture1D => SamplerType.Texture1D,
+ TextureDimensions.Texture2D => SamplerType.Texture2D,
+ TextureDimensions.Texture3D => SamplerType.Texture3D,
+ TextureDimensions.TextureCube => SamplerType.TextureCube,
+ _ => throw new ArgumentException($"Invalid texture dimensions \"{dimensions}\".")
+ };
}
private static SamplerType ConvertSamplerType(TextureTarget type)
diff --git a/Ryujinx.Graphics.Shader/IntermediateRepresentation/TextureOperation.cs b/Ryujinx.Graphics.Shader/IntermediateRepresentation/TextureOperation.cs
index 718d2c2e..06541f90 100644
--- a/Ryujinx.Graphics.Shader/IntermediateRepresentation/TextureOperation.cs
+++ b/Ryujinx.Graphics.Shader/IntermediateRepresentation/TextureOperation.cs
@@ -7,6 +7,8 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
public int Handle { get; private set; }
+ public TextureFormat Format { get; set; }
+
public TextureOperation(
Instruction inst,
SamplerType type,
diff --git a/Ryujinx.Graphics.Shader/QueryInfoName.cs b/Ryujinx.Graphics.Shader/QueryInfoName.cs
index 887c0d7d..41f42cbd 100644
--- a/Ryujinx.Graphics.Shader/QueryInfoName.cs
+++ b/Ryujinx.Graphics.Shader/QueryInfoName.cs
@@ -11,6 +11,7 @@ namespace Ryujinx.Graphics.Shader
IsTextureRectangle,
PrimitiveTopology,
StorageBufferOffsetAlignment,
- SupportsNonConstantTextureOffset
+ SupportsNonConstantTextureOffset,
+ TextureFormat
}
} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/StructuredIr/AstTextureOperation.cs b/Ryujinx.Graphics.Shader/StructuredIr/AstTextureOperation.cs
index 5473978e..a3fa3e3a 100644
--- a/Ryujinx.Graphics.Shader/StructuredIr/AstTextureOperation.cs
+++ b/Ryujinx.Graphics.Shader/StructuredIr/AstTextureOperation.cs
@@ -4,8 +4,9 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
{
class AstTextureOperation : AstOperation
{
- public SamplerType Type { get; }
- public TextureFlags Flags { get; }
+ public SamplerType Type { get; }
+ public TextureFormat Format { get; }
+ public TextureFlags Flags { get; }
public int Handle { get; }
public int ArraySize { get; }
@@ -13,6 +14,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
public AstTextureOperation(
Instruction inst,
SamplerType type,
+ TextureFormat format,
TextureFlags flags,
int handle,
int arraySize,
@@ -20,6 +22,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
params IAstNode[] sources) : base(inst, index, sources)
{
Type = type;
+ Format = format;
Flags = flags;
Handle = handle;
ArraySize = arraySize;
diff --git a/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgram.cs b/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgram.cs
index 4758b08f..f1dd08f2 100644
--- a/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgram.cs
+++ b/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgram.cs
@@ -57,6 +57,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
return new AstTextureOperation(
inst,
texOp.Type,
+ texOp.Format,
texOp.Flags,
texOp.Handle,
4, // TODO: Non-hardcoded array size.
@@ -118,6 +119,11 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
if (operation is TextureOperation texOp)
{
+ if (texOp.Inst == Instruction.ImageLoad || texOp.Inst == Instruction.ImageStore)
+ {
+ dest.VarType = texOp.Format.GetComponentType();
+ }
+
AstTextureOperation astTexOp = GetAstTextureOperation(texOp);
if (texOp.Inst == Instruction.ImageLoad)
diff --git a/Ryujinx.Graphics.Shader/TextureFormat.cs b/Ryujinx.Graphics.Shader/TextureFormat.cs
new file mode 100644
index 00000000..fb4e5b03
--- /dev/null
+++ b/Ryujinx.Graphics.Shader/TextureFormat.cs
@@ -0,0 +1,128 @@
+using Ryujinx.Graphics.Shader.StructuredIr;
+
+namespace Ryujinx.Graphics.Shader
+{
+ public enum TextureFormat
+ {
+ Unknown,
+ R8Unorm,
+ R8Snorm,
+ R8Uint,
+ R8Sint,
+ R16Float,
+ R16Unorm,
+ R16Snorm,
+ R16Uint,
+ R16Sint,
+ R32Float,
+ R32Uint,
+ R32Sint,
+ R8G8Unorm,
+ R8G8Snorm,
+ R8G8Uint,
+ R8G8Sint,
+ R16G16Float,
+ R16G16Unorm,
+ R16G16Snorm,
+ R16G16Uint,
+ R16G16Sint,
+ R32G32Float,
+ R32G32Uint,
+ R32G32Sint,
+ R8G8B8A8Unorm,
+ R8G8B8A8Snorm,
+ R8G8B8A8Uint,
+ R8G8B8A8Sint,
+ R16G16B16A16Float,
+ R16G16B16A16Unorm,
+ R16G16B16A16Snorm,
+ R16G16B16A16Uint,
+ R16G16B16A16Sint,
+ R32G32B32A32Float,
+ R32G32B32A32Uint,
+ R32G32B32A32Sint,
+ R10G10B10A2Unorm,
+ R10G10B10A2Uint,
+ R11G11B10Float
+ }
+
+ static class TextureFormatExtensions
+ {
+ public static string ToGlslFormat(this TextureFormat format)
+ {
+ return format switch
+ {
+ TextureFormat.R8Unorm => "r8",
+ TextureFormat.R8Snorm => "r8_snorm",
+ TextureFormat.R8Uint => "r8ui",
+ TextureFormat.R8Sint => "r8i",
+ TextureFormat.R16Float => "r16f",
+ TextureFormat.R16Unorm => "r16",
+ TextureFormat.R16Snorm => "r16_snorm",
+ TextureFormat.R16Uint => "r16ui",
+ TextureFormat.R16Sint => "r16i",
+ TextureFormat.R32Float => "r32f",
+ TextureFormat.R32Uint => "r32ui",
+ TextureFormat.R32Sint => "r32i",
+ TextureFormat.R8G8Unorm => "rg8",
+ TextureFormat.R8G8Snorm => "rg8_snorm",
+ TextureFormat.R8G8Uint => "rg8ui",
+ TextureFormat.R8G8Sint => "rg8i",
+ TextureFormat.R16G16Float => "rg16f",
+ TextureFormat.R16G16Unorm => "rg16",
+ TextureFormat.R16G16Snorm => "rg16_snorm",
+ TextureFormat.R16G16Uint => "rg16ui",
+ TextureFormat.R16G16Sint => "rg16i",
+ TextureFormat.R32G32Float => "rg32f",
+ TextureFormat.R32G32Uint => "rg32ui",
+ TextureFormat.R32G32Sint => "rg32i",
+ TextureFormat.R8G8B8A8Unorm => "rgba8",
+ TextureFormat.R8G8B8A8Snorm => "rgba8_snorm",
+ TextureFormat.R8G8B8A8Uint => "rgba8ui",
+ TextureFormat.R8G8B8A8Sint => "rgba8i",
+ TextureFormat.R16G16B16A16Float => "rgba16f",
+ TextureFormat.R16G16B16A16Unorm => "rgba16",
+ TextureFormat.R16G16B16A16Snorm => "rgba16_snorm",
+ TextureFormat.R16G16B16A16Uint => "rgba16ui",
+ TextureFormat.R16G16B16A16Sint => "rgba16i",
+ TextureFormat.R32G32B32A32Float => "rgba32f",
+ TextureFormat.R32G32B32A32Uint => "rgba32ui",
+ TextureFormat.R32G32B32A32Sint => "rgba32i",
+ TextureFormat.R10G10B10A2Unorm => "rgb10_a2",
+ TextureFormat.R10G10B10A2Uint => "rgb10_a2ui",
+ TextureFormat.R11G11B10Float => "r11f_g11f_b10f",
+ _ => string.Empty
+ };
+ }
+
+ public static VariableType GetComponentType(this TextureFormat format)
+ {
+ switch (format)
+ {
+ case TextureFormat.R8Uint:
+ case TextureFormat.R16Uint:
+ case TextureFormat.R32Uint:
+ case TextureFormat.R8G8Uint:
+ case TextureFormat.R16G16Uint:
+ case TextureFormat.R32G32Uint:
+ case TextureFormat.R8G8B8A8Uint:
+ case TextureFormat.R16G16B16A16Uint:
+ case TextureFormat.R32G32B32A32Uint:
+ case TextureFormat.R10G10B10A2Uint:
+ return VariableType.U32;
+ case TextureFormat.R8Sint:
+ case TextureFormat.R16Sint:
+ case TextureFormat.R32Sint:
+ case TextureFormat.R8G8Sint:
+ case TextureFormat.R16G16Sint:
+ case TextureFormat.R32G32Sint:
+ case TextureFormat.R8G8B8A8Sint:
+ case TextureFormat.R16G16B16A16Sint:
+ case TextureFormat.R32G32B32A32Sint:
+ return VariableType.S32;
+ };
+
+ return VariableType.F32;
+ }
+ }
+}
diff --git a/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs b/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs
index 60660847..3035ebf6 100644
--- a/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs
+++ b/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs
@@ -102,6 +102,8 @@ namespace Ryujinx.Graphics.Shader.Translation
return 16;
case QueryInfoName.SupportsNonConstantTextureOffset:
return Convert.ToInt32(true);
+ case QueryInfoName.TextureFormat:
+ return (int)TextureFormat.R8G8B8A8Unorm;
}
}