aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Ryujinx.Common/Utilities/BitUtils.cs35
-rw-r--r--Ryujinx.Graphics/DepthCompareFunc.cs14
-rw-r--r--Ryujinx.Graphics/Gal/GalImage.cs36
-rw-r--r--Ryujinx.Graphics/Gal/GalTextureSampler.cs10
-rw-r--r--Ryujinx.Graphics/Gal/GalTextureTarget.cs15
-rw-r--r--Ryujinx.Graphics/Gal/IGalRenderTarget.cs24
-rw-r--r--Ryujinx.Graphics/Gal/IGalTexture.cs2
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/ImageHandler.cs1
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs25
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/OGLExtension.cs7
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/OGLRenderTarget.cs55
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs2
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs256
-rw-r--r--Ryujinx.Graphics/Gal/Shader/GlslDecl.cs26
-rw-r--r--Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs320
-rw-r--r--Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs613
-rw-r--r--Ryujinx.Graphics/Gal/Shader/ShaderDecodeOpCode.cs5
-rw-r--r--Ryujinx.Graphics/Gal/Shader/ShaderIrInst.cs1
-rw-r--r--Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTex.cs18
-rw-r--r--Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs2
-rw-r--r--Ryujinx.Graphics/Gal/ShaderDeclInfo.cs23
-rw-r--r--Ryujinx.Graphics/GpuResourceManager.cs33
-rw-r--r--Ryujinx.Graphics/Graphics3d/NvGpuEngine2d.cs96
-rw-r--r--Ryujinx.Graphics/Graphics3d/NvGpuEngine2dReg.cs2
-rw-r--r--Ryujinx.Graphics/Graphics3d/NvGpuEngine3d.cs14
-rw-r--r--Ryujinx.Graphics/Graphics3d/NvGpuEngine3dReg.cs217
-rw-r--r--Ryujinx.Graphics/Graphics3d/NvGpuEngineM2mf.cs21
-rw-r--r--Ryujinx.Graphics/Graphics3d/NvGpuEngineP2mf.cs8
-rw-r--r--Ryujinx.Graphics/Graphics3d/Texture/ASTCDecoder.cs1
-rw-r--r--Ryujinx.Graphics/Graphics3d/Texture/BlockLinearSwizzle.cs165
-rw-r--r--Ryujinx.Graphics/Graphics3d/Texture/ISwizzle.cs8
-rw-r--r--Ryujinx.Graphics/Graphics3d/Texture/ImageUtils.cs241
-rw-r--r--Ryujinx.Graphics/Graphics3d/Texture/LinearSwizzle.cs36
-rw-r--r--Ryujinx.Graphics/Graphics3d/Texture/TextureFactory.cs65
-rw-r--r--Ryujinx.Graphics/Graphics3d/Texture/TextureHelper.cs17
-rw-r--r--Ryujinx.Graphics/Texture/TextureInstructionSuffix.cs19
-rw-r--r--Ryujinx.Graphics/VDec/VideoDecoder.cs7
-rw-r--r--Ryujinx.HLE/HOS/Services/Vi/NvFlinger.cs6
-rw-r--r--Ryujinx.ShaderTools/Program.cs2
39 files changed, 2081 insertions, 367 deletions
diff --git a/Ryujinx.Common/Utilities/BitUtils.cs b/Ryujinx.Common/Utilities/BitUtils.cs
index 135b397d..b6fba4fb 100644
--- a/Ryujinx.Common/Utilities/BitUtils.cs
+++ b/Ryujinx.Common/Utilities/BitUtils.cs
@@ -34,6 +34,11 @@ namespace Ryujinx.Common
return value & -(long)size;
}
+ public static int DivRoundUp(int value, int dividend)
+ {
+ return (value + dividend - 1) / dividend;
+ }
+
public static ulong DivRoundUp(ulong value, uint dividend)
{
return (value + dividend - 1) / dividend;
@@ -44,6 +49,24 @@ namespace Ryujinx.Common
return (value + dividend - 1) / dividend;
}
+ public static int Pow2RoundUp(int value)
+ {
+ value--;
+
+ value |= (value >> 1);
+ value |= (value >> 2);
+ value |= (value >> 4);
+ value |= (value >> 8);
+ value |= (value >> 16);
+
+ return ++value;
+ }
+
+ public static int Pow2RoundDown(int value)
+ {
+ return IsPowerOfTwo32(value) ? value : Pow2RoundUp(value) >> 1;
+ }
+
public static bool IsPowerOfTwo32(int value)
{
return value != 0 && (value & (value - 1)) == 0;
@@ -85,6 +108,18 @@ namespace Ryujinx.Common
return (ulong)count;
}
+ public static int CountTrailingZeros32(int value)
+ {
+ int count = 0;
+
+ while (((value >> count) & 1) == 0)
+ {
+ count++;
+ }
+
+ return count;
+ }
+
public static long ReverseBits64(long value)
{
return (long)ReverseBits64((ulong)value);
diff --git a/Ryujinx.Graphics/DepthCompareFunc.cs b/Ryujinx.Graphics/DepthCompareFunc.cs
new file mode 100644
index 00000000..24c8854a
--- /dev/null
+++ b/Ryujinx.Graphics/DepthCompareFunc.cs
@@ -0,0 +1,14 @@
+namespace Ryujinx.Graphics
+{
+ public enum DepthCompareFunc
+ {
+ Never = 0,
+ Less = 1,
+ Equal = 2,
+ LEqual = 3,
+ Greater = 4,
+ NotEqual = 5,
+ GEqual = 6,
+ Always = 7
+ }
+}
diff --git a/Ryujinx.Graphics/Gal/GalImage.cs b/Ryujinx.Graphics/Gal/GalImage.cs
index 92f43cc9..fb904b09 100644
--- a/Ryujinx.Graphics/Gal/GalImage.cs
+++ b/Ryujinx.Graphics/Gal/GalImage.cs
@@ -6,9 +6,15 @@ namespace Ryujinx.Graphics.Gal
{
public int Width;
public int Height;
+
+ // FIXME: separate layer and depth
+ public int Depth;
+ public int LayerCount;
public int TileWidth;
public int GobBlockHeight;
+ public int GobBlockDepth;
public int Pitch;
+ public int MaxMipmapLevel;
public GalImageFormat Format;
public GalMemoryLayout Layout;
@@ -16,34 +22,45 @@ namespace Ryujinx.Graphics.Gal
public GalTextureSource YSource;
public GalTextureSource ZSource;
public GalTextureSource WSource;
+ public GalTextureTarget TextureTarget;
public GalImage(
int Width,
int Height,
+ int Depth,
+ int LayerCount,
int TileWidth,
int GobBlockHeight,
+ int GobBlockDepth,
GalMemoryLayout Layout,
GalImageFormat Format,
- GalTextureSource XSource = GalTextureSource.Red,
- GalTextureSource YSource = GalTextureSource.Green,
- GalTextureSource ZSource = GalTextureSource.Blue,
- GalTextureSource WSource = GalTextureSource.Alpha)
+ GalTextureTarget TextureTarget,
+ int MaxMipmapLevel = 1,
+ GalTextureSource XSource = GalTextureSource.Red,
+ GalTextureSource YSource = GalTextureSource.Green,
+ GalTextureSource ZSource = GalTextureSource.Blue,
+ GalTextureSource WSource = GalTextureSource.Alpha)
{
this.Width = Width;
this.Height = Height;
+ this.LayerCount = LayerCount;
+ this.Depth = Depth;
this.TileWidth = TileWidth;
this.GobBlockHeight = GobBlockHeight;
+ this.GobBlockDepth = GobBlockDepth;
this.Layout = Layout;
this.Format = Format;
+ this.MaxMipmapLevel = MaxMipmapLevel;
this.XSource = XSource;
this.YSource = YSource;
this.ZSource = ZSource;
this.WSource = WSource;
+ this.TextureTarget = TextureTarget;
Pitch = ImageUtils.GetPitch(Format, Width);
}
- public bool SizeMatches(GalImage Image)
+ public bool SizeMatches(GalImage Image, bool IgnoreLayer = false)
{
if (ImageUtils.GetBytesPerPixel(Format) !=
ImageUtils.GetBytesPerPixel(Image.Format))
@@ -57,7 +74,14 @@ namespace Ryujinx.Graphics.Gal
return false;
}
- return Height == Image.Height;
+ bool Result = Height == Image.Height && Depth == Image.Depth;
+
+ if (!IgnoreLayer)
+ {
+ Result = Result && LayerCount == Image.LayerCount;
+ }
+
+ return Result;
}
}
} \ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/GalTextureSampler.cs b/Ryujinx.Graphics/Gal/GalTextureSampler.cs
index b9e5c765..1d658cea 100644
--- a/Ryujinx.Graphics/Gal/GalTextureSampler.cs
+++ b/Ryujinx.Graphics/Gal/GalTextureSampler.cs
@@ -12,6 +12,9 @@ namespace Ryujinx.Graphics.Gal
public GalColorF BorderColor { get; private set; }
+ public bool DepthCompare { get; private set; }
+ public DepthCompareFunc DepthCompareFunc { get; private set; }
+
public GalTextureSampler(
GalTextureWrap AddressU,
GalTextureWrap AddressV,
@@ -19,7 +22,9 @@ namespace Ryujinx.Graphics.Gal
GalTextureFilter MinFilter,
GalTextureFilter MagFilter,
GalTextureMipFilter MipFilter,
- GalColorF BorderColor)
+ GalColorF BorderColor,
+ bool DepthCompare,
+ DepthCompareFunc DepthCompareFunc)
{
this.AddressU = AddressU;
this.AddressV = AddressV;
@@ -28,6 +33,9 @@ namespace Ryujinx.Graphics.Gal
this.MagFilter = MagFilter;
this.MipFilter = MipFilter;
this.BorderColor = BorderColor;
+
+ this.DepthCompare = DepthCompare;
+ this.DepthCompareFunc = DepthCompareFunc;
}
}
} \ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/GalTextureTarget.cs b/Ryujinx.Graphics/Gal/GalTextureTarget.cs
new file mode 100644
index 00000000..bcc0c49a
--- /dev/null
+++ b/Ryujinx.Graphics/Gal/GalTextureTarget.cs
@@ -0,0 +1,15 @@
+namespace Ryujinx.Graphics.Gal
+{
+ public enum GalTextureTarget
+ {
+ OneD = 0,
+ TwoD = 1,
+ ThreeD = 2,
+ CubeMap = 3,
+ OneDArray = 4,
+ TwoDArray = 5,
+ OneDBuffer = 6,
+ TwoDNoMipMap = 7,
+ CubeArray = 8,
+ }
+}
diff --git a/Ryujinx.Graphics/Gal/IGalRenderTarget.cs b/Ryujinx.Graphics/Gal/IGalRenderTarget.cs
index f941ccd5..90cad856 100644
--- a/Ryujinx.Graphics/Gal/IGalRenderTarget.cs
+++ b/Ryujinx.Graphics/Gal/IGalRenderTarget.cs
@@ -25,16 +25,20 @@ namespace Ryujinx.Graphics.Gal
void Render();
void Copy(
- long SrcKey,
- long DstKey,
- int SrcX0,
- int SrcY0,
- int SrcX1,
- int SrcY1,
- int DstX0,
- int DstY0,
- int DstX1,
- int DstY1);
+ GalImage SrcImage,
+ GalImage DstImage,
+ long SrcKey,
+ long DstKey,
+ int SrcLayer,
+ int DstLayer,
+ int SrcX0,
+ int SrcY0,
+ int SrcX1,
+ int SrcY1,
+ int DstX0,
+ int DstY0,
+ int DstX1,
+ int DstY1);
void Reinterpret(long Key, GalImage NewImage);
}
diff --git a/Ryujinx.Graphics/Gal/IGalTexture.cs b/Ryujinx.Graphics/Gal/IGalTexture.cs
index aeecdf1a..de4ba9cb 100644
--- a/Ryujinx.Graphics/Gal/IGalTexture.cs
+++ b/Ryujinx.Graphics/Gal/IGalTexture.cs
@@ -13,6 +13,6 @@ namespace Ryujinx.Graphics.Gal
void Bind(long Key, int Index, GalImage Image);
- void SetSampler(GalTextureSampler Sampler);
+ void SetSampler(GalImage Image, GalTextureSampler Sampler);
}
} \ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/OpenGL/ImageHandler.cs b/Ryujinx.Graphics/Gal/OpenGL/ImageHandler.cs
index 8db0b8a8..5714f3d8 100644
--- a/Ryujinx.Graphics/Gal/OpenGL/ImageHandler.cs
+++ b/Ryujinx.Graphics/Gal/OpenGL/ImageHandler.cs
@@ -8,6 +8,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
public int Width => Image.Width;
public int Height => Image.Height;
+ public int Depth => Image.Depth;
public GalImageFormat Format => Image.Format;
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs
index f2afe7b5..3a25fff7 100644
--- a/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs
+++ b/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs
@@ -189,6 +189,31 @@ namespace Ryujinx.Graphics.Gal.OpenGL
throw new NotImplementedException($"{Format & GalImageFormat.FormatMask} {Format & GalImageFormat.TypeMask}");
}
+ public static All GetDepthCompareFunc(DepthCompareFunc DepthCompareFunc)
+ {
+ switch (DepthCompareFunc)
+ {
+ case DepthCompareFunc.LEqual:
+ return All.Lequal;
+ case DepthCompareFunc.GEqual:
+ return All.Gequal;
+ case DepthCompareFunc.Less:
+ return All.Less;
+ case DepthCompareFunc.Greater:
+ return All.Greater;
+ case DepthCompareFunc.Equal:
+ return All.Equal;
+ case DepthCompareFunc.NotEqual:
+ return All.Notequal;
+ case DepthCompareFunc.Always:
+ return All.Always;
+ case DepthCompareFunc.Never:
+ return All.Never;
+ default:
+ throw new ArgumentException(nameof(DepthCompareFunc) + " \"" + DepthCompareFunc + "\" is not valid!");
+ }
+ }
+
public static InternalFormat GetCompressedImageFormat(GalImageFormat Format)
{
switch (Format)
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLExtension.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLExtension.cs
index 11daeb59..52b3d0ce 100644
--- a/Ryujinx.Graphics/Gal/OpenGL/OGLExtension.cs
+++ b/Ryujinx.Graphics/Gal/OpenGL/OGLExtension.cs
@@ -9,9 +9,12 @@ namespace Ryujinx.Graphics.Gal.OpenGL
private static Lazy<bool> s_TextureMirrorClamp = new Lazy<bool>(() => HasExtension("GL_EXT_texture_mirror_clamp"));
private static Lazy<bool> s_ViewportArray = new Lazy<bool>(() => HasExtension("GL_ARB_viewport_array"));
+ private static Lazy<bool> s_NvidiaDriver = new Lazy<bool>(() => IsNvidiaDriver());
+
public static bool EnhancedLayouts => s_EnhancedLayouts.Value;
public static bool TextureMirrorClamp => s_TextureMirrorClamp.Value;
public static bool ViewportArray => s_ViewportArray.Value;
+ public static bool NvidiaDrvier => s_NvidiaDriver.Value;
private static bool HasExtension(string Name)
{
@@ -27,5 +30,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL
return false;
}
+
+ private static bool IsNvidiaDriver() {
+ return GL.GetString(StringName.Vendor).Equals("NVIDIA Corporation");
+ }
}
} \ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLRenderTarget.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLRenderTarget.cs
index 0d7bb3cd..8dd3b37f 100644
--- a/Ryujinx.Graphics/Gal/OpenGL/OGLRenderTarget.cs
+++ b/Ryujinx.Graphics/Gal/OpenGL/OGLRenderTarget.cs
@@ -389,16 +389,20 @@ namespace Ryujinx.Graphics.Gal.OpenGL
}
public void Copy(
- long SrcKey,
- long DstKey,
- int SrcX0,
- int SrcY0,
- int SrcX1,
- int SrcY1,
- int DstX0,
- int DstY0,
- int DstX1,
- int DstY1)
+ GalImage SrcImage,
+ GalImage DstImage,
+ long SrcKey,
+ long DstKey,
+ int SrcLayer,
+ int DstLayer,
+ int SrcX0,
+ int SrcY0,
+ int SrcX1,
+ int SrcY1,
+ int DstX0,
+ int DstY0,
+ int DstX1,
+ int DstY1)
{
if (Texture.TryGetImageHandler(SrcKey, out ImageHandler SrcTex) &&
Texture.TryGetImageHandler(DstKey, out ImageHandler DstTex))
@@ -425,8 +429,24 @@ namespace Ryujinx.Graphics.Gal.OpenGL
FramebufferAttachment Attachment = GetAttachment(SrcTex);
- GL.FramebufferTexture(FramebufferTarget.ReadFramebuffer, Attachment, SrcTex.Handle, 0);
- GL.FramebufferTexture(FramebufferTarget.DrawFramebuffer, Attachment, DstTex.Handle, 0);
+ if (ImageUtils.IsArray(SrcImage.TextureTarget) && SrcLayer > 0)
+ {
+ GL.FramebufferTextureLayer(FramebufferTarget.ReadFramebuffer, Attachment, SrcTex.Handle, 0, SrcLayer);
+ }
+ else
+ {
+ GL.FramebufferTexture(FramebufferTarget.ReadFramebuffer, Attachment, SrcTex.Handle, 0);
+ }
+
+ if (ImageUtils.IsArray(DstImage.TextureTarget) && DstLayer > 0)
+ {
+ GL.FramebufferTextureLayer(FramebufferTarget.DrawFramebuffer, Attachment, DstTex.Handle, 0, DstLayer);
+ }
+ else
+ {
+ GL.FramebufferTexture(FramebufferTarget.DrawFramebuffer, Attachment, DstTex.Handle, 0);
+ }
+
BlitFramebufferFilter Filter = BlitFramebufferFilter.Nearest;
@@ -452,7 +472,10 @@ namespace Ryujinx.Graphics.Gal.OpenGL
if (NewImage.Format == OldImage.Format &&
NewImage.Width == OldImage.Width &&
- NewImage.Height == OldImage.Height)
+ NewImage.Height == OldImage.Height &&
+ NewImage.Depth == OldImage.Depth &&
+ NewImage.LayerCount == OldImage.LayerCount &&
+ NewImage.TextureTarget == OldImage.TextureTarget)
{
return;
}
@@ -477,9 +500,11 @@ namespace Ryujinx.Graphics.Gal.OpenGL
(_, PixelFormat Format, PixelType Type) = OGLEnumConverter.GetImageFormat(CachedImage.Format);
- GL.BindTexture(TextureTarget.Texture2D, CachedImage.Handle);
+ TextureTarget Target = ImageUtils.GetTextureTarget(NewImage.TextureTarget);
+
+ GL.BindTexture(Target, CachedImage.Handle);
- GL.GetTexImage(TextureTarget.Texture2D, 0, Format, Type, IntPtr.Zero);
+ GL.GetTexImage(Target, 0, Format, Type, IntPtr.Zero);
GL.BindBuffer(BufferTarget.PixelPackBuffer, 0);
GL.BindBuffer(BufferTarget.PixelUnpackBuffer, CopyPBO);
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs
index 10a9120d..dc168ff9 100644
--- a/Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs
+++ b/Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs
@@ -53,7 +53,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
{
GlslProgram Program;
- GlslDecompiler Decompiler = new GlslDecompiler(OGLLimit.MaxUboSize);
+ GlslDecompiler Decompiler = new GlslDecompiler(OGLLimit.MaxUboSize, OGLExtension.NvidiaDrvier);
int ShaderDumpIndex = ShaderDumper.DumpIndex;
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs
index ef984b1e..4fef11d2 100644
--- a/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs
+++ b/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs
@@ -38,7 +38,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL
{
int Handle = GL.GenTexture();
- GL.BindTexture(TextureTarget.Texture2D, Handle);
+ TextureTarget Target = ImageUtils.GetTextureTarget(Image.TextureTarget);
+
+ GL.BindTexture(Target, Handle);
const int Level = 0; //TODO: Support mipmap textures.
const int Border = 0;
@@ -54,23 +56,70 @@ namespace Ryujinx.Graphics.Gal.OpenGL
PixelFormat Format,
PixelType Type) = OGLEnumConverter.GetImageFormat(Image.Format);
- GL.TexImage2D(
- TextureTarget.Texture2D,
- Level,
- InternalFmt,
- Image.Width,
- Image.Height,
- Border,
- Format,
- Type,
- IntPtr.Zero);
+ switch (Target)
+ {
+ case TextureTarget.Texture1D:
+ GL.TexImage1D(
+ Target,
+ Level,
+ InternalFmt,
+ Image.Width,
+ Border,
+ Format,
+ Type,
+ IntPtr.Zero);
+ break;
+
+ case TextureTarget.Texture2D:
+ GL.TexImage2D(
+ Target,
+ Level,
+ InternalFmt,
+ Image.Width,
+ Image.Height,
+ Border,
+ Format,
+ Type,
+ IntPtr.Zero);
+ break;
+ case TextureTarget.Texture3D:
+ GL.TexImage3D(
+ Target,
+ Level,
+ InternalFmt,
+ Image.Width,
+ Image.Height,
+ Image.Depth,
+ Border,
+ Format,
+ Type,
+ IntPtr.Zero);
+ break;
+ case TextureTarget.Texture2DArray:
+ GL.TexImage3D(
+ Target,
+ Level,
+ InternalFmt,
+ Image.Width,
+ Image.Height,
+ Image.LayerCount,
+ Border,
+ Format,
+ Type,
+ IntPtr.Zero);
+ break;
+ default:
+ throw new NotImplementedException($"Unsupported texture target type: {Target}");
+ }
}
public void Create(long Key, byte[] Data, GalImage Image)
{
int Handle = GL.GenTexture();
- GL.BindTexture(TextureTarget.Texture2D, Handle);
+ TextureTarget Target = ImageUtils.GetTextureTarget(Image.TextureTarget);
+
+ GL.BindTexture(Target, Handle);
const int Level = 0; //TODO: Support mipmap textures.
const int Border = 0;
@@ -81,15 +130,56 @@ namespace Ryujinx.Graphics.Gal.OpenGL
{
InternalFormat InternalFmt = OGLEnumConverter.GetCompressedImageFormat(Image.Format);
- GL.CompressedTexImage2D(
- TextureTarget.Texture2D,
- Level,
- InternalFmt,
- Image.Width,
- Image.Height,
- Border,
- Data.Length,
- Data);
+ switch (Target)
+ {
+ case TextureTarget.Texture1D:
+ GL.CompressedTexImage1D(
+ Target,
+ Level,
+ InternalFmt,
+ Image.Width,
+ Border,
+ Data.Length,
+ Data);
+ break;
+ case TextureTarget.Texture2D:
+ GL.CompressedTexImage2D(
+ Target,
+ Level,
+ InternalFmt,
+ Image.Width,
+ Image.Height,
+ Border,
+ Data.Length,
+ Data);
+ break;
+ case TextureTarget.Texture3D:
+ GL.CompressedTexImage3D(
+ Target,
+ Level,
+ InternalFmt,
+ Image.Width,
+ Image.Height,
+ Image.Depth,
+ Border,
+ Data.Length,
+ Data);
+ break;
+ case TextureTarget.Texture2DArray:
+ GL.CompressedTexImage3D(
+ Target,
+ Level,
+ InternalFmt,
+ Image.Width,
+ Image.Height,
+ Image.LayerCount,
+ Border,
+ Data.Length,
+ Data);
+ break;
+ default:
+ throw new NotImplementedException($"Unsupported texture target type: {Target}");
+ }
}
else
{
@@ -98,13 +188,16 @@ namespace Ryujinx.Graphics.Gal.OpenGL
{
int TextureBlockWidth = ImageUtils.GetBlockWidth(Image.Format);
int TextureBlockHeight = ImageUtils.GetBlockHeight(Image.Format);
+ int TextureBlockDepth = ImageUtils.GetBlockDepth(Image.Format);
Data = ASTCDecoder.DecodeToRGBA8888(
Data,
TextureBlockWidth,
- TextureBlockHeight, 1,
+ TextureBlockHeight,
+ TextureBlockDepth,
Image.Width,
- Image.Height, 1);
+ Image.Height,
+ Image.Depth);
Image.Format = GalImageFormat.RGBA8 | (Image.Format & GalImageFormat.TypeMask);
}
@@ -113,16 +206,80 @@ namespace Ryujinx.Graphics.Gal.OpenGL
PixelFormat Format,
PixelType Type) = OGLEnumConverter.GetImageFormat(Image.Format);
- GL.TexImage2D(
- TextureTarget.Texture2D,
- Level,
- InternalFmt,
- Image.Width,
- Image.Height,
- Border,
- Format,
- Type,
- Data);
+
+ switch (Target)
+ {
+ case TextureTarget.Texture1D:
+ GL.TexImage1D(
+ Target,
+ Level,
+ InternalFmt,
+ Image.Width,
+ Border,
+ Format,
+ Type,
+ Data);
+ break;
+ case TextureTarget.Texture2D:
+ GL.TexImage2D(
+ Target,
+ Level,
+ InternalFmt,
+ Image.Width,
+ Image.Height,
+ Border,
+ Format,
+ Type,
+ Data);
+ break;
+ case TextureTarget.Texture3D:
+ GL.TexImage3D(
+ Target,
+ Level,
+ InternalFmt,
+ Image.Width,
+ Image.Height,
+ Image.Depth,
+ Border,
+ Format,
+ Type,
+ Data);
+ break;
+ case TextureTarget.Texture2DArray:
+ GL.TexImage3D(
+ Target,
+ Level,
+ InternalFmt,
+ Image.Width,
+ Image.Height,
+ Image.LayerCount,
+ Border,
+ Format,
+ Type,
+ Data);
+ break;
+ case TextureTarget.TextureCubeMap:
+ Span<byte> Array = new Span<byte>(Data);
+
+ int FaceSize = ImageUtils.GetSize(Image) / 6;
+
+ for (int Face = 0; Face < 6; Face++)
+ {
+ GL.TexImage2D(
+ TextureTarget.TextureCubeMapPositiveX + Face,
+ Level,
+ InternalFmt,
+ Image.Width,
+ Image.Height,
+ Border,
+ Format,
+ Type,
+ Array.Slice(Face * FaceSize, FaceSize).ToArray());
+ }
+ break;
+ default:
+ throw new NotImplementedException($"Unsupported texture target type: {Target}");
+ }
}
}
@@ -165,7 +322,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL
{
GL.ActiveTexture(TextureUnit.Texture0 + Index);
- GL.BindTexture(TextureTarget.Texture2D, CachedImage.Handle);
+ TextureTarget Target = ImageUtils.GetTextureTarget(Image.TextureTarget);
+
+ GL.BindTexture(Target, CachedImage.Handle);
int[] SwizzleRgba = new int[]
{
@@ -175,23 +334,27 @@ namespace Ryujinx.Graphics.Gal.OpenGL
(int)OGLEnumConverter.GetTextureSwizzle(Image.WSource)
};
- GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleRgba, SwizzleRgba);
+ GL.TexParameter(Target, TextureParameterName.TextureSwizzleRgba, SwizzleRgba);
}
}
- public void SetSampler(GalTextureSampler Sampler)
+ public void SetSampler(GalImage Image, GalTextureSampler Sampler)
{
int WrapS = (int)OGLEnumConverter.GetTextureWrapMode(Sampler.AddressU);
int WrapT = (int)OGLEnumConverter.GetTextureWrapMode(Sampler.AddressV);
+ int WrapR = (int)OGLEnumConverter.GetTextureWrapMode(Sampler.AddressP);
int MinFilter = (int)OGLEnumConverter.GetTextureMinFilter(Sampler.MinFilter, Sampler.MipFilter);
int MagFilter = (int)OGLEnumConverter.GetTextureMagFilter(Sampler.MagFilter);
- GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, WrapS);
- GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, WrapT);
+ TextureTarget Target = ImageUtils.GetTextureTarget(Image.TextureTarget);
- GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, MinFilter);
- GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, MagFilter);
+ GL.TexParameter(Target, TextureParameterName.TextureWrapS, WrapS);
+ GL.TexParameter(Target, TextureParameterName.TextureWrapT, WrapT);
+ GL.TexParameter(Target, TextureParameterName.TextureWrapR, WrapR);
+
+ GL.TexParameter(Target, TextureParameterName.TextureMinFilter, MinFilter);
+ GL.TexParameter(Target, TextureParameterName.TextureMagFilter, MagFilter);
float[] Color = new float[]
{
@@ -201,7 +364,18 @@ namespace Ryujinx.Graphics.Gal.OpenGL
Sampler.BorderColor.Alpha
};
- GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureBorderColor, Color);
+ GL.TexParameter(Target, TextureParameterName.TextureBorderColor, Color);
+
+ if (Sampler.DepthCompare)
+ {
+ GL.TexParameter(Target, TextureParameterName.TextureCompareMode, (int)All.CompareRToTexture);
+ GL.TexParameter(Target, TextureParameterName.TextureCompareFunc, (int)OGLEnumConverter.GetDepthCompareFunc(Sampler.DepthCompareFunc));
+ }
+ else
+ {
+ GL.TexParameter(Target, TextureParameterName.TextureCompareMode, (int)All.None);
+ GL.TexParameter(Target, TextureParameterName.TextureCompareFunc, (int)All.Never);
+ }
}
}
}
diff --git a/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs b/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs
index 43923da7..f7ae34fa 100644
--- a/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs
+++ b/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs
@@ -1,3 +1,5 @@
+using Ryujinx.Graphics.Gal.OpenGL;
+using Ryujinx.Graphics.Texture;
using System;
using System.Collections.Generic;
@@ -224,6 +226,7 @@ namespace Ryujinx.Graphics.Gal.Shader
if (Op.Inst == ShaderIrInst.Texq ||
Op.Inst == ShaderIrInst.Texs ||
+ Op.Inst == ShaderIrInst.Tld4 ||
Op.Inst == ShaderIrInst.Txlf)
{
int Handle = ((ShaderIrOperImm)Op.OperandC).Value;
@@ -232,7 +235,25 @@ namespace Ryujinx.Graphics.Gal.Shader
string Name = StagePrefix + TextureName + Index;
- m_Textures.TryAdd(Handle, new ShaderDeclInfo(Name, Handle));
+ GalTextureTarget TextureTarget;
+
+ TextureInstructionSuffix TextureInstructionSuffix;
+
+ // TODO: Non 2D texture type for TEXQ?
+ if (Op.Inst == ShaderIrInst.Texq)
+ {
+ TextureTarget = GalTextureTarget.TwoD;
+ TextureInstructionSuffix = TextureInstructionSuffix.None;
+ }
+ else
+ {
+ ShaderIrMetaTex Meta = ((ShaderIrMetaTex)Op.MetaData);
+
+ TextureTarget = Meta.TextureTarget;
+ TextureInstructionSuffix = Meta.TextureInstructionSuffix;
+ }
+
+ m_Textures.TryAdd(Handle, new ShaderDeclInfo(Name, Handle, false, 0, 1, TextureTarget, TextureInstructionSuffix));
}
else if (Op.Inst == ShaderIrInst.Texb)
{
@@ -257,9 +278,10 @@ namespace Ryujinx.Graphics.Gal.Shader
if (HandleSrc != null && HandleSrc is ShaderIrOperCbuf Cbuf)
{
+ ShaderIrMetaTex Meta = ((ShaderIrMetaTex)Op.MetaData);
string Name = StagePrefix + TextureName + "_cb" + Cbuf.Index + "_" + Cbuf.Pos;
- m_CbTextures.Add(Op, new ShaderDeclInfo(Name, Cbuf.Pos, true, Cbuf.Index));
+ m_CbTextures.Add(Op, new ShaderDeclInfo(Name, Cbuf.Pos, true, Cbuf.Index, 1, Meta.TextureTarget, Meta.TextureInstructionSuffix));
}
else
{
diff --git a/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs b/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs
index 854c827e..5f809525 100644
--- a/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs
+++ b/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs
@@ -1,3 +1,5 @@
+using OpenTK.Graphics.OpenGL;
+using Ryujinx.Graphics.Texture;
using System;
using System.Collections.Generic;
using System.Globalization;
@@ -33,7 +35,9 @@ namespace Ryujinx.Graphics.Gal.Shader
public int MaxUboSize { get; }
- public GlslDecompiler(int MaxUboSize)
+ private bool IsNvidiaDriver;
+
+ public GlslDecompiler(int MaxUboSize, bool IsNvidiaDriver)
{
InstsExpr = new Dictionary<ShaderIrInst, GetInstExpr>()
{
@@ -103,6 +107,7 @@ namespace Ryujinx.Graphics.Gal.Shader
{ ShaderIrInst.Texb, GetTexbExpr },
{ ShaderIrInst.Texq, GetTexqExpr },
{ ShaderIrInst.Texs, GetTexsExpr },
+ { ShaderIrInst.Tld4, GetTld4Expr },
{ ShaderIrInst.Trunc, GetTruncExpr },
{ ShaderIrInst.Txlf, GetTxlfExpr },
{ ShaderIrInst.Utof, GetUtofExpr },
@@ -110,6 +115,7 @@ namespace Ryujinx.Graphics.Gal.Shader
};
this.MaxUboSize = MaxUboSize / 16;
+ this.IsNvidiaDriver = IsNvidiaDriver;
}
public GlslProgram Decompile(
@@ -219,14 +225,70 @@ namespace Ryujinx.Graphics.Gal.Shader
}
}
+ private string GetSamplerType(TextureTarget TextureTarget, bool HasShadow)
+ {
+ string Result;
+
+ switch (TextureTarget)
+ {
+ case TextureTarget.Texture1D:
+ Result = "sampler1D";
+ break;
+ case TextureTarget.Texture2D:
+ Result = "sampler2D";
+ break;
+ case TextureTarget.Texture3D:
+ Result = "sampler3D";
+ break;
+ case TextureTarget.TextureCubeMap:
+ Result = "samplerCube";
+ break;
+ case TextureTarget.TextureRectangle:
+ Result = "sampler2DRect";
+ break;
+ case TextureTarget.Texture1DArray:
+ Result = "sampler1DArray";
+ break;
+ case TextureTarget.Texture2DArray:
+ Result = "sampler2DArray";
+ break;
+ case TextureTarget.TextureCubeMapArray:
+ Result = "samplerCubeArray";
+ break;
+ case TextureTarget.TextureBuffer:
+ Result = "samplerBuffer";
+ break;
+ case TextureTarget.Texture2DMultisample:
+ Result = "sampler2DMS";
+ break;
+ case TextureTarget.Texture2DMultisampleArray:
+ Result = "sampler2DMSArray";
+ break;
+ default:
+ throw new NotSupportedException();
+ }
+
+ if (HasShadow)
+ Result += "Shadow";
+
+ return Result;
+ }
+
private void PrintDeclTextures()
{
foreach (ShaderDeclInfo DeclInfo in IterateCbTextures())
{
- SB.AppendLine("uniform sampler2D " + DeclInfo.Name + ";");
+ TextureTarget Target = ImageUtils.GetTextureTarget(DeclInfo.TextureTarget);
+ SB.AppendLine($"// {DeclInfo.TextureSuffix}");
+ SB.AppendLine("uniform " + GetSamplerType(Target, (DeclInfo.TextureSuffix & TextureInstructionSuffix.DC) != 0) + " " + DeclInfo.Name + ";");
}
- PrintDecls(Decl.Textures, "uniform sampler2D");
+ foreach (ShaderDeclInfo DeclInfo in Decl.Textures.Values.OrderBy(DeclKeySelector))
+ {
+ TextureTarget Target = ImageUtils.GetTextureTarget(DeclInfo.TextureTarget);
+ SB.AppendLine($"// {DeclInfo.TextureSuffix}");
+ SB.AppendLine("uniform " + GetSamplerType(Target, (DeclInfo.TextureSuffix & TextureInstructionSuffix.DC) != 0) + " " + DeclInfo.Name + ";");
+ }
}
private IEnumerable<ShaderDeclInfo> IterateCbTextures()
@@ -778,6 +840,7 @@ namespace Ryujinx.Graphics.Gal.Shader
case ShaderIrInst.Ipa:
case ShaderIrInst.Texq:
case ShaderIrInst.Texs:
+ case ShaderIrInst.Tld4:
case ShaderIrInst.Txlf:
return false;
}
@@ -1124,7 +1187,7 @@ namespace Ryujinx.Graphics.Gal.Shader
string Ch = "rgba".Substring(Meta.Elem, 1);
- return "texture(" + DeclInfo.Name + ", " + Coords + ")." + Ch;
+ return GetTextureOperation(Op, DeclInfo.Name, Coords, Ch);
}
private string GetTexqExpr(ShaderIrOp Op)
@@ -1157,20 +1220,50 @@ namespace Ryujinx.Graphics.Gal.Shader
string Ch = "rgba".Substring(Meta.Elem, 1);
- return "texture(" + Sampler + ", " + Coords + ")." + Ch;
+ return GetTextureOperation(Op, Sampler, Coords, Ch);
+ }
+
+ private string GetTld4Expr(ShaderIrOp Op)
+ {
+ ShaderIrMetaTex Meta = (ShaderIrMetaTex)Op.MetaData;
+
+ string Sampler = GetTexSamplerName(Op);
+
+ string Coords = GetTexSamplerCoords(Op);
+
+ string Ch = "rgba".Substring(Meta.Elem, 1);
+
+ return GetTextureGatherOperation(Op, Sampler, Coords, Ch);
}
+ // TODO: support AOFFI on non nvidia drivers
private string GetTxlfExpr(ShaderIrOp Op)
{
+ // TODO: Support all suffixes
ShaderIrMetaTex Meta = (ShaderIrMetaTex)Op.MetaData;
+ TextureInstructionSuffix Suffix = Meta.TextureInstructionSuffix;
+
string Sampler = GetTexSamplerName(Op);
string Coords = GetITexSamplerCoords(Op);
string Ch = "rgba".Substring(Meta.Elem, 1);
- return "texelFetch(" + Sampler + ", " + Coords + ", 0)." + Ch;
+ string Lod = "0";
+
+ if (Meta.LevelOfDetail != null)
+ {
+ Lod = GetOperExpr(Op, Meta.LevelOfDetail);
+ }
+
+ if ((Suffix & TextureInstructionSuffix.AOffI) != 0 && IsNvidiaDriver)
+ {
+ string Offset = GetTextureOffset(Meta, GetOperExpr(Op, Meta.Offset));
+ return "texelFetchOffset(" + Sampler + ", " + Coords + ", " + Lod + ", " + Offset + ")." + Ch;
+ }
+
+ return "texelFetch(" + Sampler + ", " + Coords + ", " + Lod + ")." + Ch;
}
private string GetTruncExpr(ShaderIrOp Op) => GetUnaryCall(Op, "trunc");
@@ -1246,14 +1339,205 @@ namespace Ryujinx.Graphics.Gal.Shader
private string GetTexSamplerCoords(ShaderIrOp Op)
{
- return "vec2(" + GetOperExpr(Op, Op.OperandA) + ", " +
- GetOperExpr(Op, Op.OperandB) + ")";
+ ShaderIrMetaTex Meta = (ShaderIrMetaTex)Op.MetaData;
+
+ bool HasDepth = (Meta.TextureInstructionSuffix & TextureInstructionSuffix.DC) != 0;
+
+ int Coords = ImageUtils.GetCoordsCountTextureTarget(Meta.TextureTarget);
+
+ bool IsArray = ImageUtils.IsArray(Meta.TextureTarget);
+
+
+ string GetLastArgument(ShaderIrNode Node)
+ {
+ string Result = GetOperExpr(Op, Node);
+
+ // array index is actually an integer so we need to pass it correctly
+ if (IsArray)
+ {
+ Result = "float(floatBitsToInt(" + Result + "))";
+ }
+
+ return Result;
+ }
+
+ string LastArgument;
+ string DepthArgument = "";
+
+ int VecSize = Coords;
+ if (HasDepth && Op.Inst != ShaderIrInst.Tld4)
+ {
+ VecSize++;
+ DepthArgument = $", {GetOperExpr(Op, Meta.DepthCompare)}";
+ }
+
+ switch (Coords)
+ {
+ case 1:
+ if (HasDepth)
+ {
+ return $"vec3({GetOperExpr(Op, Meta.Coordinates[0])}, 0.0{DepthArgument})";
+ }
+
+ return GetOperExpr(Op, Meta.Coordinates[0]);
+ case 2:
+ LastArgument = GetLastArgument(Meta.Coordinates[1]);
+
+ return $"vec{VecSize}({GetOperExpr(Op, Meta.Coordinates[0])}, {LastArgument}{DepthArgument})";
+ case 3:
+ LastArgument = GetLastArgument(Meta.Coordinates[2]);
+
+ return $"vec{VecSize}({GetOperExpr(Op, Meta.Coordinates[0])}, {GetOperExpr(Op, Meta.Coordinates[1])}, {LastArgument}{DepthArgument})";
+ case 4:
+ LastArgument = GetLastArgument(Meta.Coordinates[3]);
+
+ return $"vec4({GetOperExpr(Op, Meta.Coordinates[0])}, {GetOperExpr(Op, Meta.Coordinates[1])}, {GetOperExpr(Op, Meta.Coordinates[2])}, {LastArgument}){DepthArgument}";
+ default:
+ throw new InvalidOperationException();
+ }
+
+ }
+
+ private string GetTextureOffset(ShaderIrMetaTex Meta, string Oper, int Shift = 4, int Mask = 0xF)
+ {
+ string GetOffset(string Operation, int Index)
+ {
+ return $"({Operation} >> {Index * Shift}) & 0x{Mask:x}";
+ }
+
+ int Coords = ImageUtils.GetCoordsCountTextureTarget(Meta.TextureTarget);
+
+ if (ImageUtils.IsArray(Meta.TextureTarget))
+ Coords -= 1;
+
+ switch (Coords)
+ {
+ case 1:
+ return GetOffset(Oper, 0);
+ case 2:
+ return "ivec2(" + GetOffset(Oper, 0) + ", " + GetOffset(Oper, 1) + ")";
+ case 3:
+ return "ivec3(" + GetOffset(Oper, 0) + ", " + GetOffset(Oper, 1) + ", " + GetOffset(Oper, 2) + ")";
+ case 4:
+ return "ivec4(" + GetOffset(Oper, 0) + ", " + GetOffset(Oper, 1) + ", " + GetOffset(Oper, 2) + ", " + GetOffset(Oper, 3) + ")";
+ default:
+ throw new InvalidOperationException();
+ }
+ }
+
+ // TODO: support AOFFI on non nvidia drivers
+ private string GetTextureGatherOperation(ShaderIrOp Op, string Sampler, string Coords, string Ch)
+ {
+ ShaderIrMetaTex Meta = (ShaderIrMetaTex)Op.MetaData;
+
+ TextureInstructionSuffix Suffix = Meta.TextureInstructionSuffix;
+
+ string ChString = "." + Ch;
+
+ string Comp = Meta.Component.ToString();
+
+ if ((Suffix & TextureInstructionSuffix.DC) != 0)
+ {
+ Comp = GetOperExpr(Op, Meta.DepthCompare);
+ }
+
+ if ((Suffix & TextureInstructionSuffix.AOffI) != 0 && IsNvidiaDriver)
+ {
+ string Offset = GetTextureOffset(Meta, "floatBitsToInt((" + GetOperExpr(Op, Meta.Offset) + "))", 8, 0x3F);
+
+ if ((Suffix & TextureInstructionSuffix.DC) != 0)
+ {
+ return "textureGatherOffset(" + Sampler + ", " + Coords + ", " + Comp + ", " + Offset + ")" + ChString;
+ }
+
+ return "textureGatherOffset(" + Sampler + ", " + Coords + ", " + Offset + ", " + Comp + ")" + ChString;
+ }
+ // TODO: Support PTP
+ else if ((Suffix & TextureInstructionSuffix.PTP) != 0)
+ {
+ throw new NotImplementedException();
+ }
+
+ return "textureGather(" + Sampler + ", " + Coords + ", " + Comp + ")" + ChString;
+ }
+
+ // TODO: support AOFFI on non nvidia drivers
+ private string GetTextureOperation(ShaderIrOp Op, string Sampler, string Coords, string Ch)
+ {
+ ShaderIrMetaTex Meta = (ShaderIrMetaTex)Op.MetaData;
+
+ TextureInstructionSuffix Suffix = Meta.TextureInstructionSuffix;
+
+ string ChString = "." + Ch;
+
+ if ((Suffix & TextureInstructionSuffix.DC) != 0)
+ {
+ ChString = "";
+ }
+
+ // TODO: Support LBA and LLA
+ if ((Suffix & TextureInstructionSuffix.LZ) != 0)
+ {
+ if ((Suffix & TextureInstructionSuffix.AOffI) != 0 && IsNvidiaDriver)
+ {
+ string Offset = GetTextureOffset(Meta, "floatBitsToInt((" + GetOperExpr(Op, Meta.Offset) + "))");
+
+ return "textureLodOffset(" + Sampler + ", " + Coords + ", 0.0, " + Offset + ")" + ChString;
+ }
+
+ return "textureLod(" + Sampler + ", " + Coords + ", 0.0)" + ChString;
+ }
+ else if ((Suffix & TextureInstructionSuffix.LB) != 0)
+ {
+ if ((Suffix & TextureInstructionSuffix.AOffI) != 0 && IsNvidiaDriver)
+ {
+ string Offset = GetTextureOffset(Meta, "floatBitsToInt((" + GetOperExpr(Op, Meta.Offset) + "))");
+
+ return "textureOffset(" + Sampler + ", " + Coords + ", " + Offset + ", " + GetOperExpr(Op, Meta.LevelOfDetail) + ")" + ChString;
+ }
+
+ return "texture(" + Sampler + ", " + Coords + ", " + GetOperExpr(Op, Meta.LevelOfDetail) + ")" + ChString;
+ }
+ else if ((Suffix & TextureInstructionSuffix.LL) != 0)
+ {
+ if ((Suffix & TextureInstructionSuffix.AOffI) != 0 && IsNvidiaDriver)
+ {
+ string Offset = GetTextureOffset(Meta, "floatBitsToInt((" + GetOperExpr(Op, Meta.Offset) + "))");
+
+ return "textureLodOffset(" + Sampler + ", " + Coords + ", " + GetOperExpr(Op, Meta.LevelOfDetail) + ", " + Offset + ")" + ChString;
+ }
+
+ return "textureLod(" + Sampler + ", " + Coords + ", " + GetOperExpr(Op, Meta.LevelOfDetail) + ")" + ChString;
+ }
+ else if ((Suffix & TextureInstructionSuffix.AOffI) != 0 && IsNvidiaDriver)
+ {
+ string Offset = GetTextureOffset(Meta, "floatBitsToInt((" + GetOperExpr(Op, Meta.Offset) + "))");
+
+ return "textureOffset(" + Sampler + ", " + Coords + ", " + Offset + ")" + ChString;
+ }
+ else
+ {
+ return "texture(" + Sampler + ", " + Coords + ")" + ChString;
+ }
+ throw new NotImplementedException($"Texture Suffix {Meta.TextureInstructionSuffix} is not implemented");
+
}
private string GetITexSamplerCoords(ShaderIrOp Op)
{
- return "ivec2(" + GetOperExpr(Op, Op.OperandA) + ", " +
- GetOperExpr(Op, Op.OperandB) + ")";
+ ShaderIrMetaTex Meta = (ShaderIrMetaTex)Op.MetaData;
+
+ switch (ImageUtils.GetCoordsCountTextureTarget(Meta.TextureTarget))
+ {
+ case 1:
+ return GetOperExpr(Op, Meta.Coordinates[0]);
+ case 2:
+ return "ivec2(" + GetOperExpr(Op, Meta.Coordinates[0]) + ", " + GetOperExpr(Op, Meta.Coordinates[1]) + ")";
+ case 3:
+ return "ivec3(" + GetOperExpr(Op, Meta.Coordinates[0]) + ", " + GetOperExpr(Op, Meta.Coordinates[1]) + ", " + GetOperExpr(Op, Meta.Coordinates[2]) + ")";
+ default:
+ throw new InvalidOperationException();
+ }
}
private string GetOperExpr(ShaderIrOp Op, ShaderIrNode Oper)
@@ -1292,22 +1576,6 @@ namespace Ryujinx.Graphics.Gal.Shader
}
break;
}
-
- case ShaderIrOperImm Imm:
- {
- //For integer immediates being used as float,
- //it's better (for readability) to just return the float value.
- if (DstType == OperType.F32)
- {
- float Value = BitConverter.Int32BitsToSingle(Imm.Value);
-
- if (!float.IsNaN(Value) && !float.IsInfinity(Value))
- {
- return GetFloatConst(Value);
- }
- }
- break;
- }
}
switch (DstType)
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs
index adcc47b9..8b4eacdf 100644
--- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs
@@ -1,3 +1,4 @@
+using Ryujinx.Graphics.Texture;
using System;
using static Ryujinx.Graphics.Gal.Shader.ShaderDecodeHelper;
@@ -29,6 +30,75 @@ namespace Ryujinx.Graphics.Gal.Shader
{ RGB_, RG_A, R_BA, _GBA, RGBA, ____, ____, ____ }
};
+ private static GalTextureTarget TexToTextureTarget(int TexType, bool IsArray)
+ {
+ switch (TexType)
+ {
+ case 0:
+ return IsArray ? GalTextureTarget.OneDArray : GalTextureTarget.OneD;
+ case 2:
+ return IsArray ? GalTextureTarget.TwoDArray : GalTextureTarget.TwoD;
+ case 4:
+ if (IsArray)
+ throw new InvalidOperationException($"ARRAY bit set on a TEX with 3D texture!");
+ return GalTextureTarget.ThreeD;
+ case 6:
+ return IsArray ? GalTextureTarget.CubeArray : GalTextureTarget.CubeMap;
+ default:
+ throw new InvalidOperationException();
+ }
+ }
+
+ private static GalTextureTarget TexsToTextureTarget(int TexType)
+ {
+ switch (TexType)
+ {
+ case 0:
+ return GalTextureTarget.OneD;
+ case 2:
+ case 4:
+ case 6:
+ case 8:
+ case 0xa:
+ case 0xc:
+ return GalTextureTarget.TwoD;
+ case 0xe:
+ case 0x10:
+ case 0x12:
+ return GalTextureTarget.TwoDArray;
+ case 0x14:
+ case 0x16:
+ return GalTextureTarget.ThreeD;
+ case 0x18:
+ case 0x1a:
+ return GalTextureTarget.CubeMap;
+ default:
+ throw new InvalidOperationException();
+ }
+ }
+
+ public static GalTextureTarget TldsToTextureTarget(int TexType)
+ {
+ switch (TexType)
+ {
+ case 0:
+ case 2:
+ return GalTextureTarget.OneD;
+ case 4:
+ case 8:
+ case 0xa:
+ case 0xc:
+ case 0x18:
+ return GalTextureTarget.TwoD;
+ case 0x10:
+ return GalTextureTarget.TwoDArray;
+ case 0xe:
+ return GalTextureTarget.ThreeD;
+ default:
+ throw new InvalidOperationException();
+ }
+ }
+
public static void Ld_A(ShaderIrBlock Block, long OpCode, int Position)
{
ShaderIrNode[] Opers = OpCode.Abuf20();
@@ -132,43 +202,166 @@ namespace Ryujinx.Graphics.Gal.Shader
public static void Tex(ShaderIrBlock Block, long OpCode, int Position)
{
- EmitTex(Block, OpCode, GprHandle: false);
+ TextureInstructionSuffix Suffix;
+
+ int RawSuffix = OpCode.Read(0x34, 0x38);
+
+ switch (RawSuffix)
+ {
+ case 0:
+ Suffix = TextureInstructionSuffix.None;
+ break;
+ case 0x8:
+ Suffix = TextureInstructionSuffix.LZ;
+ break;
+ case 0x10:
+ Suffix = TextureInstructionSuffix.LB;
+ break;
+ case 0x18:
+ Suffix = TextureInstructionSuffix.LL;
+ break;
+ case 0x30:
+ Suffix = TextureInstructionSuffix.LBA;
+ break;
+ case 0x38:
+ Suffix = TextureInstructionSuffix.LLA;
+ break;
+ default:
+ throw new InvalidOperationException($"Invalid Suffix for TEX instruction {RawSuffix}");
+ }
+
+ bool IsOffset = OpCode.Read(0x36);
+
+ if (IsOffset)
+ Suffix |= TextureInstructionSuffix.AOffI;
+
+ EmitTex(Block, OpCode, Suffix, GprHandle: false);
}
public static void Tex_B(ShaderIrBlock Block, long OpCode, int Position)
{
- EmitTex(Block, OpCode, GprHandle: true);
+ TextureInstructionSuffix Suffix;
+
+ int RawSuffix = OpCode.Read(0x24, 0xe);
+
+ switch (RawSuffix)
+ {
+ case 0:
+ Suffix = TextureInstructionSuffix.None;
+ break;
+ case 0x2:
+ Suffix = TextureInstructionSuffix.LZ;
+ break;
+ case 0x4:
+ Suffix = TextureInstructionSuffix.LB;
+ break;
+ case 0x6:
+ Suffix = TextureInstructionSuffix.LL;
+ break;
+ case 0xc:
+ Suffix = TextureInstructionSuffix.LBA;
+ break;
+ case 0xe:
+ Suffix = TextureInstructionSuffix.LLA;
+ break;
+ default:
+ throw new InvalidOperationException($"Invalid Suffix for TEX.B instruction {RawSuffix}");
+ }
+
+ bool IsOffset = OpCode.Read(0x23);
+
+ if (IsOffset)
+ Suffix |= TextureInstructionSuffix.AOffI;
+
+ EmitTex(Block, OpCode, Suffix, GprHandle: true);
}
- private static void EmitTex(ShaderIrBlock Block, long OpCode, bool GprHandle)
+ private static void EmitTex(ShaderIrBlock Block, long OpCode, TextureInstructionSuffix TextureInstructionSuffix, bool GprHandle)
{
- //TODO: Support other formats.
- ShaderIrOperGpr[] Coords = new ShaderIrOperGpr[2];
+ bool IsArray = OpCode.HasArray();
+
+ GalTextureTarget TextureTarget = TexToTextureTarget(OpCode.Read(28, 6), IsArray);
+
+ bool HasDepthCompare = OpCode.Read(0x32);
+
+ if (HasDepthCompare)
+ {
+ TextureInstructionSuffix |= TextureInstructionSuffix.DC;
+ }
- for (int Index = 0; Index < Coords.Length; Index++)
+ ShaderIrOperGpr[] Coords = new ShaderIrOperGpr[ImageUtils.GetCoordsCountTextureTarget(TextureTarget)];
+
+ int IndexExtraCoord = 0;
+
+ if (IsArray)
+ {
+ IndexExtraCoord++;
+
+ Coords[Coords.Length - 1] = OpCode.Gpr8();
+ }
+
+
+ for (int Index = 0; Index < Coords.Length - IndexExtraCoord; Index++)
{
ShaderIrOperGpr CoordReg = OpCode.Gpr8();
CoordReg.Index += Index;
+ CoordReg.Index += IndexExtraCoord;
+
if (!CoordReg.IsValidRegister)
{
CoordReg.Index = ShaderIrOperGpr.ZRIndex;
}
- Coords[Index] = ShaderIrOperGpr.MakeTemporary(Index);
-
- Block.AddNode(new ShaderIrAsg(Coords[Index], CoordReg));
+ Coords[Index] = CoordReg;
}
int ChMask = OpCode.Read(31, 0xf);
+ ShaderIrOperGpr LevelOfDetail = null;
+ ShaderIrOperGpr Offset = null;
+ ShaderIrOperGpr DepthCompare = null;
+
+ // TODO: determine first argument when TEX.B is used
+ int OperBIndex = GprHandle ? 1 : 0;
+
+ if ((TextureInstructionSuffix & TextureInstructionSuffix.LL) != 0 ||
+ (TextureInstructionSuffix & TextureInstructionSuffix.LB) != 0 ||
+ (TextureInstructionSuffix & TextureInstructionSuffix.LBA) != 0 ||
+ (TextureInstructionSuffix & TextureInstructionSuffix.LLA) != 0)
+ {
+ LevelOfDetail = OpCode.Gpr20();
+ LevelOfDetail.Index += OperBIndex;
+
+ OperBIndex++;
+ }
+
+ if ((TextureInstructionSuffix & TextureInstructionSuffix.AOffI) != 0)
+ {
+ Offset = OpCode.Gpr20();
+ Offset.Index += OperBIndex;
+
+ OperBIndex++;
+ }
+
+ if ((TextureInstructionSuffix & TextureInstructionSuffix.DC) != 0)
+ {
+ DepthCompare = OpCode.Gpr20();
+ DepthCompare.Index += OperBIndex;
+
+ OperBIndex++;
+ }
+
+ // ???
ShaderIrNode OperC = GprHandle
? (ShaderIrNode)OpCode.Gpr20()
: (ShaderIrNode)OpCode.Imm13_36();
ShaderIrInst Inst = GprHandle ? ShaderIrInst.Texb : ShaderIrInst.Texs;
+ Coords = CoordsRegistersToTempRegisters(Block, Coords);
+
int RegInc = 0;
for (int Ch = 0; Ch < 4; Ch++)
@@ -187,9 +380,14 @@ namespace Ryujinx.Graphics.Gal.Shader
continue;
}
- ShaderIrMetaTex Meta = new ShaderIrMetaTex(Ch);
+ ShaderIrMetaTex Meta = new ShaderIrMetaTex(Ch, TextureTarget, TextureInstructionSuffix, Coords)
+ {
+ LevelOfDetail = LevelOfDetail,
+ Offset = Offset,
+ DepthCompare = DepthCompare
+ };
- ShaderIrOp Op = new ShaderIrOp(Inst, Coords[0], Coords[1], OperC, Meta);
+ ShaderIrOp Op = new ShaderIrOp(Inst, Coords[0], Coords.Length > 1 ? Coords[1] : null, OperC, Meta);
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(Dst, Op)));
}
@@ -197,17 +395,238 @@ namespace Ryujinx.Graphics.Gal.Shader
public static void Texs(ShaderIrBlock Block, long OpCode, int Position)
{
- EmitTexs(Block, OpCode, ShaderIrInst.Texs);
+ TextureInstructionSuffix Suffix;
+
+ int RawSuffix = OpCode.Read(0x34, 0x1e);
+
+ switch (RawSuffix)
+ {
+ case 0:
+ case 0x4:
+ case 0x10:
+ case 0x16:
+ Suffix = TextureInstructionSuffix.LZ;
+ break;
+ case 0x6:
+ case 0x1a:
+ Suffix = TextureInstructionSuffix.LL;
+ break;
+ case 0x8:
+ Suffix = TextureInstructionSuffix.DC;
+ break;
+ case 0x2:
+ case 0xe:
+ case 0x14:
+ case 0x18:
+ Suffix = TextureInstructionSuffix.None;
+ break;
+ case 0xa:
+ Suffix = TextureInstructionSuffix.LL | TextureInstructionSuffix.DC;
+ break;
+ case 0xc:
+ case 0x12:
+ Suffix = TextureInstructionSuffix.LZ | TextureInstructionSuffix.DC;
+ break;
+ default:
+ throw new InvalidOperationException($"Invalid Suffix for TEXS instruction {RawSuffix}");
+ }
+
+ GalTextureTarget TextureTarget = TexsToTextureTarget(OpCode.Read(52, 0x1e));
+
+ EmitTexs(Block, OpCode, ShaderIrInst.Texs, TextureTarget, Suffix);
}
public static void Tlds(ShaderIrBlock Block, long OpCode, int Position)
{
- EmitTexs(Block, OpCode, ShaderIrInst.Txlf);
+ TextureInstructionSuffix Suffix;
+
+ int RawSuffix = OpCode.Read(0x34, 0x1e);
+
+ switch (RawSuffix)
+ {
+ case 0:
+ case 0x4:
+ case 0x8:
+ Suffix = TextureInstructionSuffix.LZ | TextureInstructionSuffix.AOffI;
+ break;
+ case 0xc:
+ Suffix = TextureInstructionSuffix.LZ | TextureInstructionSuffix.MZ;
+ break;
+ case 0xe:
+ case 0x10:
+ Suffix = TextureInstructionSuffix.LZ;
+ break;
+ case 0x2:
+ case 0xa:
+ Suffix = TextureInstructionSuffix.LL;
+ break;
+ case 0x18:
+ Suffix = TextureInstructionSuffix.LL | TextureInstructionSuffix.AOffI;
+ break;
+ default:
+ throw new InvalidOperationException($"Invalid Suffix for TLDS instruction {RawSuffix}");
+ }
+
+ GalTextureTarget TextureTarget = TldsToTextureTarget(OpCode.Read(52, 0x1e));
+
+ EmitTexs(Block, OpCode, ShaderIrInst.Txlf, TextureTarget, Suffix);
+ }
+
+ public static void Tld4(ShaderIrBlock Block, long OpCode, int Position)
+ {
+ TextureInstructionSuffix Suffix;
+
+ int RawSuffix = OpCode.Read(0x34, 0xc);
+
+ switch (RawSuffix)
+ {
+ case 0:
+ Suffix = TextureInstructionSuffix.None;
+ break;
+ case 0x4:
+ Suffix = TextureInstructionSuffix.AOffI;
+ break;
+ case 0x8:
+ Suffix = TextureInstructionSuffix.PTP;
+ break;
+ default:
+ throw new InvalidOperationException($"Invalid Suffix for TLD4 instruction {RawSuffix}");
+ }
+
+ bool IsShadow = OpCode.Read(0x32);
+
+ bool IsArray = OpCode.HasArray();
+ int ChMask = OpCode.Read(31, 0xf);
+
+ GalTextureTarget TextureTarget = TexToTextureTarget(OpCode.Read(28, 6), IsArray);
+
+ if (IsShadow)
+ {
+ Suffix |= TextureInstructionSuffix.DC;
+ }
+
+ EmitTld4(Block, OpCode, TextureTarget, Suffix, ChMask, OpCode.Read(0x38, 0x3), false);
+ }
+
+ public static void Tld4s(ShaderIrBlock Block, long OpCode, int Position)
+ {
+ TextureInstructionSuffix Suffix = TextureInstructionSuffix.None;
+
+ bool IsOffset = OpCode.Read(0x33);
+ bool IsShadow = OpCode.Read(0x32);
+
+ if (IsOffset)
+ {
+ Suffix |= TextureInstructionSuffix.AOffI;
+ }
+
+ if (IsShadow)
+ {
+ Suffix |= TextureInstructionSuffix.DC;
+ }
+
+ // TLD4S seems to only support 2D textures with RGBA mask?
+ EmitTld4(Block, OpCode, GalTextureTarget.TwoD, Suffix, RGBA, OpCode.Read(0x34, 0x3), true);
}
- private static void EmitTexs(ShaderIrBlock Block, long OpCode, ShaderIrInst Inst)
+ private static void EmitTexs(ShaderIrBlock Block,
+ long OpCode,
+ ShaderIrInst Inst,
+ GalTextureTarget TextureTarget,
+ TextureInstructionSuffix TextureInstructionSuffix)
{
- //TODO: Support other formats.
+ if (Inst == ShaderIrInst.Txlf && TextureTarget == GalTextureTarget.CubeArray)
+ {
+ throw new InvalidOperationException("TLDS instructions cannot use CUBE modifier!");
+ }
+
+ bool IsArray = ImageUtils.IsArray(TextureTarget);
+
+ ShaderIrOperGpr[] Coords = new ShaderIrOperGpr[ImageUtils.GetCoordsCountTextureTarget(TextureTarget)];
+
+ ShaderIrOperGpr OperA = OpCode.Gpr8();
+ ShaderIrOperGpr OperB = OpCode.Gpr20();
+
+ ShaderIrOperGpr SuffixExtra = OpCode.Gpr20();
+ SuffixExtra.Index += 1;
+
+ int CoordStartIndex = 0;
+
+ if (IsArray)
+ {
+ CoordStartIndex++;
+ Coords[Coords.Length - 1] = OpCode.Gpr8();
+ }
+
+ switch (Coords.Length - CoordStartIndex)
+ {
+ case 1:
+ Coords[0] = OpCode.Gpr8();
+
+ break;
+ case 2:
+ Coords[0] = OpCode.Gpr8();
+ Coords[0].Index += CoordStartIndex;
+
+ break;
+ case 3:
+ Coords[0] = OpCode.Gpr8();
+ Coords[0].Index += CoordStartIndex;
+
+ Coords[1] = OpCode.Gpr8();
+ Coords[1].Index += 1 + CoordStartIndex;
+
+ break;
+ default:
+ throw new NotSupportedException($"{Coords.Length - CoordStartIndex} coords textures aren't supported in TEXS");
+ }
+
+ int OperBIndex = 0;
+
+ ShaderIrOperGpr LevelOfDetail = null;
+ ShaderIrOperGpr Offset = null;
+ ShaderIrOperGpr DepthCompare = null;
+
+ // OperB is always the last value
+ // Not applicable to 1d textures
+ if (Coords.Length - CoordStartIndex != 1)
+ {
+ Coords[Coords.Length - CoordStartIndex - 1] = OperB;
+ OperBIndex++;
+ }
+
+ // Encoding of TEXS/TLDS is a bit special and change for 2d textures
+ // NOTE: OperA seems to hold at best two args.
+ // On 2D textures, if no suffix need an additional values, Y is stored in OperB, otherwise coords are in OperA and the additional values is in OperB.
+ if (TextureInstructionSuffix != TextureInstructionSuffix.None && TextureInstructionSuffix != TextureInstructionSuffix.LZ && TextureTarget == GalTextureTarget.TwoD)
+ {
+ Coords[Coords.Length - CoordStartIndex - 1] = OpCode.Gpr8();
+ Coords[Coords.Length - CoordStartIndex - 1].Index += Coords.Length - CoordStartIndex - 1;
+ OperBIndex--;
+ }
+
+ // TODO: Find what MZ does and what changes about the encoding (Maybe Multisample?)
+ if ((TextureInstructionSuffix & TextureInstructionSuffix.LL) != 0)
+ {
+ LevelOfDetail = OpCode.Gpr20();
+ LevelOfDetail.Index += OperBIndex;
+ OperBIndex++;
+ }
+
+ if ((TextureInstructionSuffix & TextureInstructionSuffix.AOffI) != 0)
+ {
+ Offset = OpCode.Gpr20();
+ Offset.Index += OperBIndex;
+ OperBIndex++;
+ }
+
+ if ((TextureInstructionSuffix & TextureInstructionSuffix.DC) != 0)
+ {
+ DepthCompare = OpCode.Gpr20();
+ DepthCompare.Index += OperBIndex;
+ OperBIndex++;
+ }
+
int LutIndex;
LutIndex = !OpCode.Gpr0().IsConst ? 1 : 0;
@@ -276,12 +695,7 @@ namespace Ryujinx.Graphics.Gal.Shader
}
ShaderIrNode OperC = OpCode.Imm13_36();
-
- ShaderIrOperGpr Coord0 = ShaderIrOperGpr.MakeTemporary(0);
- ShaderIrOperGpr Coord1 = ShaderIrOperGpr.MakeTemporary(1);
-
- Block.AddNode(new ShaderIrAsg(Coord0, OpCode.Gpr8()));
- Block.AddNode(new ShaderIrAsg(Coord1, OpCode.Gpr20()));
+ Coords = CoordsRegistersToTempRegisters(Block, Coords);
for (int Ch = 0; Ch < 4; Ch++)
{
@@ -290,9 +704,13 @@ namespace Ryujinx.Graphics.Gal.Shader
continue;
}
- ShaderIrMetaTex Meta = new ShaderIrMetaTex(Ch);
-
- ShaderIrOp Op = new ShaderIrOp(Inst, Coord0, Coord1, OperC, Meta);
+ ShaderIrMetaTex Meta = new ShaderIrMetaTex(Ch, TextureTarget, TextureInstructionSuffix, Coords)
+ {
+ LevelOfDetail = LevelOfDetail,
+ Offset = Offset,
+ DepthCompare = DepthCompare
+ };
+ ShaderIrOp Op = new ShaderIrOp(Inst, OperA, OperB, OperC, Meta);
ShaderIrOperGpr Dst = GetDst();
@@ -303,9 +721,156 @@ namespace Ryujinx.Graphics.Gal.Shader
}
}
+ private static void EmitTld4(ShaderIrBlock Block, long OpCode, GalTextureTarget TextureType, TextureInstructionSuffix TextureInstructionSuffix, int ChMask, int Component, bool Scalar)
+ {
+ ShaderIrOperGpr OperA = OpCode.Gpr8();
+ ShaderIrOperGpr OperB = OpCode.Gpr20();
+ ShaderIrOperImm OperC = OpCode.Imm13_36();
+
+ ShaderIrOperGpr[] Coords = new ShaderIrOperGpr[ImageUtils.GetCoordsCountTextureTarget(TextureType)];
+
+ ShaderIrOperGpr Offset = null;
+ ShaderIrOperGpr DepthCompare = null;
+
+ bool IsArray = ImageUtils.IsArray(TextureType);
+
+ int OperBIndex = 0;
+
+ if (Scalar)
+ {
+ int CoordStartIndex = 0;
+
+ if (IsArray)
+ {
+ CoordStartIndex++;
+ Coords[Coords.Length - 1] = OperB;
+ }
+
+ switch (Coords.Length - CoordStartIndex)
+ {
+ case 1:
+ Coords[0] = OpCode.Gpr8();
+
+ break;
+ case 2:
+ Coords[0] = OpCode.Gpr8();
+ Coords[0].Index += CoordStartIndex;
+
+ break;
+ case 3:
+ Coords[0] = OpCode.Gpr8();
+ Coords[0].Index += CoordStartIndex;
+
+ Coords[1] = OpCode.Gpr8();
+ Coords[1].Index += 1 + CoordStartIndex;
+
+ break;
+ default:
+ throw new NotSupportedException($"{Coords.Length - CoordStartIndex} coords textures aren't supported in TLD4S");
+ }
+
+ if (Coords.Length - CoordStartIndex != 1)
+ {
+ Coords[Coords.Length - CoordStartIndex - 1] = OperB;
+ OperBIndex++;
+ }
+
+ if (TextureInstructionSuffix != TextureInstructionSuffix.None && TextureType == GalTextureTarget.TwoD)
+ {
+ Coords[Coords.Length - CoordStartIndex - 1] = OpCode.Gpr8();
+ Coords[Coords.Length - CoordStartIndex - 1].Index += Coords.Length - CoordStartIndex - 1;
+ OperBIndex--;
+ }
+ }
+ else
+ {
+ int IndexExtraCoord = 0;
+
+ if (IsArray)
+ {
+ IndexExtraCoord++;
+
+ Coords[Coords.Length - 1] = OpCode.Gpr8();
+ }
+
+ for (int Index = 0; Index < Coords.Length - IndexExtraCoord; Index++)
+ {
+ Coords[Index] = OpCode.Gpr8();
+
+ Coords[Index].Index += Index;
+
+ Coords[Index].Index += IndexExtraCoord;
+
+ if (Coords[Index].Index > ShaderIrOperGpr.ZRIndex)
+ {
+ Coords[Index].Index = ShaderIrOperGpr.ZRIndex;
+ }
+ }
+ }
+
+ if ((TextureInstructionSuffix & TextureInstructionSuffix.AOffI) != 0)
+ {
+ Offset = OpCode.Gpr20();
+ Offset.Index += OperBIndex;
+ OperBIndex++;
+ }
+
+ if ((TextureInstructionSuffix & TextureInstructionSuffix.DC) != 0)
+ {
+ DepthCompare = OpCode.Gpr20();
+ DepthCompare.Index += OperBIndex;
+ OperBIndex++;
+ }
+
+ Coords = CoordsRegistersToTempRegisters(Block, Coords);
+
+ int RegInc = 0;
+
+ for (int Ch = 0; Ch < 4; Ch++)
+ {
+ if (!IsChannelUsed(ChMask, Ch))
+ {
+ continue;
+ }
+
+ ShaderIrOperGpr Dst = OpCode.Gpr0();
+
+ Dst.Index += RegInc++;
+
+ if (!Dst.IsValidRegister || Dst.IsConst)
+ {
+ continue;
+ }
+
+ ShaderIrMetaTex Meta = new ShaderIrMetaTex(Ch, TextureType, TextureInstructionSuffix, Coords)
+ {
+ Component = Component,
+ Offset = Offset,
+ DepthCompare = DepthCompare
+ };
+
+ ShaderIrOp Op = new ShaderIrOp(ShaderIrInst.Tld4, OperA, OperB, OperC, Meta);
+
+ Block.AddNode(OpCode.PredNode(new ShaderIrAsg(Dst, Op)));
+ }
+ }
+
private static bool IsChannelUsed(int ChMask, int Ch)
{
return (ChMask & (1 << Ch)) != 0;
}
+
+ private static ShaderIrOperGpr[] CoordsRegistersToTempRegisters(ShaderIrBlock Block, params ShaderIrOperGpr[] Registers)
+ {
+ ShaderIrOperGpr[] Res = new ShaderIrOperGpr[Registers.Length];
+
+ for (int Index = 0; Index < Res.Length; Index++)
+ {
+ Res[Index] = ShaderIrOperGpr.MakeTemporary(Index);
+ Block.AddNode(new ShaderIrAsg(Res[Index], Registers[Index]));
+ }
+
+ return Res;
+ }
}
} \ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeOpCode.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeOpCode.cs
index f0f92148..e241e1ca 100644
--- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeOpCode.cs
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeOpCode.cs
@@ -19,6 +19,11 @@ namespace Ryujinx.Graphics.Gal.Shader
return ((int)(OpCode >> 20) << 8) >> 8;
}
+ private static bool HasArray(this long OpCode)
+ {
+ return OpCode.Read(0x1c);
+ }
+
private static ShaderIrOperAbuf[] Abuf20(this long OpCode)
{
int Abuf = OpCode.Read(20, 0x3ff);
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrInst.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrInst.cs
index 35dea612..68ff214e 100644
--- a/Ryujinx.Graphics/Gal/Shader/ShaderIrInst.cs
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderIrInst.cs
@@ -49,6 +49,7 @@ namespace Ryujinx.Graphics.Gal.Shader
Ipa,
Texb,
Texs,
+ Tld4,
Trunc,
F_End,
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTex.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTex.cs
index 82f3bb77..72ea221a 100644
--- a/Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTex.cs
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTex.cs
@@ -1,12 +1,24 @@
+using Ryujinx.Graphics.Texture;
+
namespace Ryujinx.Graphics.Gal.Shader
{
class ShaderIrMetaTex : ShaderIrMeta
{
- public int Elem { get; private set; }
+ public int Elem { get; private set; }
+ public GalTextureTarget TextureTarget { get; private set; }
+ public ShaderIrNode[] Coordinates { get; private set; }
+ public TextureInstructionSuffix TextureInstructionSuffix { get; private set; }
+ public ShaderIrOperGpr LevelOfDetail;
+ public ShaderIrOperGpr Offset;
+ public ShaderIrOperGpr DepthCompare;
+ public int Component; // for TLD4(S)
- public ShaderIrMetaTex(int Elem)
+ public ShaderIrMetaTex(int Elem, GalTextureTarget TextureTarget, TextureInstructionSuffix TextureInstructionSuffix, params ShaderIrNode[] Coordinates)
{
- this.Elem = Elem;
+ this.Elem = Elem;
+ this.TextureTarget = TextureTarget;
+ this.TextureInstructionSuffix = TextureInstructionSuffix;
+ this.Coordinates = Coordinates;
}
}
} \ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs b/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs
index 177e36c3..d2bbd38c 100644
--- a/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs
@@ -122,6 +122,8 @@ namespace Ryujinx.Graphics.Gal.Shader
Set("1101111101001x", ShaderDecode.Texq);
Set("1101x00xxxxxxx", ShaderDecode.Texs);
Set("1101101xxxxxxx", ShaderDecode.Tlds);
+ Set("110010xxxx111x", ShaderDecode.Tld4);
+ Set("1101111100xxxx", ShaderDecode.Tld4s);
Set("01011111xxxxxx", ShaderDecode.Vmad);
Set("0100111xxxxxxx", ShaderDecode.Xmad_CR);
Set("0011011x00xxxx", ShaderDecode.Xmad_I);
diff --git a/Ryujinx.Graphics/Gal/ShaderDeclInfo.cs b/Ryujinx.Graphics/Gal/ShaderDeclInfo.cs
index ef47ca2e..ed1955cd 100644
--- a/Ryujinx.Graphics/Gal/ShaderDeclInfo.cs
+++ b/Ryujinx.Graphics/Gal/ShaderDeclInfo.cs
@@ -1,3 +1,5 @@
+using Ryujinx.Graphics.Texture;
+
namespace Ryujinx.Graphics.Gal
{
public class ShaderDeclInfo
@@ -9,18 +11,27 @@ namespace Ryujinx.Graphics.Gal
public int Cbuf { get; private set; }
public int Size { get; private set; }
+ public GalTextureTarget TextureTarget { get; private set; }
+
+ public TextureInstructionSuffix TextureSuffix { get; private set; }
+
public ShaderDeclInfo(
string Name,
int Index,
bool IsCb = false,
int Cbuf = 0,
- int Size = 1)
+ int Size = 1,
+ GalTextureTarget TextureTarget = GalTextureTarget.TwoD,
+ TextureInstructionSuffix TextureSuffix = TextureInstructionSuffix.None)
{
- this.Name = Name;
- this.Index = Index;
- this.IsCb = IsCb;
- this.Cbuf = Cbuf;
- this.Size = Size;
+ this.Name = Name;
+ this.Index = Index;
+ this.IsCb = IsCb;
+ this.Cbuf = Cbuf;
+ this.Size = Size;
+
+ this.TextureTarget = TextureTarget;
+ this.TextureSuffix = TextureSuffix;
}
internal void Enlarge(int NewSize)
diff --git a/Ryujinx.Graphics/GpuResourceManager.cs b/Ryujinx.Graphics/GpuResourceManager.cs
index d4612951..4f2d92b0 100644
--- a/Ryujinx.Graphics/GpuResourceManager.cs
+++ b/Ryujinx.Graphics/GpuResourceManager.cs
@@ -1,6 +1,8 @@
+using Ryujinx.Common.Logging;
using Ryujinx.Graphics.Gal;
using Ryujinx.Graphics.Memory;
using Ryujinx.Graphics.Texture;
+using System;
using System.Collections.Generic;
namespace Ryujinx.Graphics
@@ -11,6 +13,7 @@ namespace Ryujinx.Graphics
{
None,
Texture,
+ TextureArrayLayer,
ColorBuffer,
ZetaBuffer
}
@@ -20,6 +23,7 @@ namespace Ryujinx.Graphics
private HashSet<long>[] UploadedKeys;
private Dictionary<long, ImageType> ImageTypes;
+ private Dictionary<long, int> MirroredTextures;
public GpuResourceManager(NvGpu Gpu)
{
@@ -33,6 +37,7 @@ namespace Ryujinx.Graphics
}
ImageTypes = new Dictionary<long, ImageType>();
+ MirroredTextures = new Dictionary<long, int>();
}
public void SendColorBuffer(NvGpuVmm Vmm, long Position, int Attachment, GalImage NewImage)
@@ -70,6 +75,32 @@ namespace Ryujinx.Graphics
ImageTypes[Position] = ImageType.Texture;
}
+ public bool TryGetTextureLayer(long Position, out int LayerIndex)
+ {
+ if (MirroredTextures.TryGetValue(Position, out LayerIndex))
+ {
+ ImageType Type = ImageTypes[Position];
+
+ // FIXME(thog): I'm actually unsure if we should deny all other image type, gpu testing needs to be done here.
+ if (Type != ImageType.Texture && Type != ImageType.TextureArrayLayer)
+ {
+ LayerIndex = -1;
+ return false;
+ }
+
+ return true;
+ }
+
+ LayerIndex = -1;
+ return false;
+ }
+
+ public void SetTextureArrayLayer(long Position, int LayerIndex)
+ {
+ ImageTypes[Position] = ImageType.TextureArrayLayer;
+ MirroredTextures[Position] = LayerIndex;
+ }
+
private void PrepareSendTexture(NvGpuVmm Vmm, long Position, GalImage NewImage)
{
long Size = ImageUtils.GetSize(NewImage);
@@ -102,7 +133,7 @@ namespace Ryujinx.Graphics
private bool TryReuse(NvGpuVmm Vmm, long Position, GalImage NewImage)
{
- if (Gpu.Renderer.Texture.TryGetImage(Position, out GalImage CachedImage) && CachedImage.SizeMatches(NewImage))
+ if (Gpu.Renderer.Texture.TryGetImage(Position, out GalImage CachedImage) && CachedImage.TextureTarget == NewImage.TextureTarget && CachedImage.SizeMatches(NewImage))
{
Gpu.Renderer.RenderTarget.Reinterpret(Position, NewImage);
diff --git a/Ryujinx.Graphics/Graphics3d/NvGpuEngine2d.cs b/Ryujinx.Graphics/Graphics3d/NvGpuEngine2d.cs
index 55e3ebd4..3295f6da 100644
--- a/Ryujinx.Graphics/Graphics3d/NvGpuEngine2d.cs
+++ b/Ryujinx.Graphics/Graphics3d/NvGpuEngine2d.cs
@@ -1,3 +1,4 @@
+using Ryujinx.Common.Logging;
using Ryujinx.Graphics.Gal;
using Ryujinx.Graphics.Memory;
using Ryujinx.Graphics.Texture;
@@ -46,6 +47,8 @@ namespace Ryujinx.Graphics.Graphics3d
bool DstLinear = ReadRegister(NvGpuEngine2dReg.DstLinear) != 0;
int DstWidth = ReadRegister(NvGpuEngine2dReg.DstWidth);
int DstHeight = ReadRegister(NvGpuEngine2dReg.DstHeight);
+ int DstDepth = ReadRegister(NvGpuEngine2dReg.DstDepth);
+ int DstLayer = ReadRegister(NvGpuEngine2dReg.DstLayer);
int DstPitch = ReadRegister(NvGpuEngine2dReg.DstPitch);
int DstBlkDim = ReadRegister(NvGpuEngine2dReg.DstBlockDimensions);
@@ -53,6 +56,8 @@ namespace Ryujinx.Graphics.Graphics3d
bool SrcLinear = ReadRegister(NvGpuEngine2dReg.SrcLinear) != 0;
int SrcWidth = ReadRegister(NvGpuEngine2dReg.SrcWidth);
int SrcHeight = ReadRegister(NvGpuEngine2dReg.SrcHeight);
+ int SrcDepth = ReadRegister(NvGpuEngine2dReg.SrcDepth);
+ int SrcLayer = ReadRegister(NvGpuEngine2dReg.SrcLayer);
int SrcPitch = ReadRegister(NvGpuEngine2dReg.SrcPitch);
int SrcBlkDim = ReadRegister(NvGpuEngine2dReg.SrcBlockDimensions);
@@ -82,26 +87,99 @@ namespace Ryujinx.Graphics.Graphics3d
long SrcKey = Vmm.GetPhysicalAddress(SrcAddress);
long DstKey = Vmm.GetPhysicalAddress(DstAddress);
+ bool IsSrcLayered = false;
+ bool IsDstLayered = false;
+
+ GalTextureTarget SrcTarget = GalTextureTarget.TwoD;
+
+ if (SrcDepth != 0)
+ {
+ SrcTarget = GalTextureTarget.TwoDArray;
+ SrcDepth++;
+ IsSrcLayered = true;
+ }
+ else
+ {
+ SrcDepth = 1;
+ }
+
+ GalTextureTarget DstTarget = GalTextureTarget.TwoD;
+
+ if (DstDepth != 0)
+ {
+ DstTarget = GalTextureTarget.TwoDArray;
+ DstDepth++;
+ IsDstLayered = true;
+ }
+ else
+ {
+ DstDepth = 1;
+ }
+
GalImage SrcTexture = new GalImage(
SrcWidth,
- SrcHeight, 1,
- SrcBlockHeight,
+ SrcHeight,
+ 1, SrcDepth, 1,
+ SrcBlockHeight, 1,
SrcLayout,
- SrcImgFormat);
+ SrcImgFormat,
+ SrcTarget);
GalImage DstTexture = new GalImage(
DstWidth,
- DstHeight, 1,
- DstBlockHeight,
+ DstHeight,
+ 1, DstDepth, 1,
+ DstBlockHeight, 1,
DstLayout,
- DstImgFormat);
+ DstImgFormat,
+ DstTarget);
SrcTexture.Pitch = SrcPitch;
DstTexture.Pitch = DstPitch;
+ long GetLayerOffset(GalImage Image, int Layer)
+ {
+ int TargetMipLevel = Image.MaxMipmapLevel <= 1 ? 1 : Image.MaxMipmapLevel - 1;
+ return ImageUtils.GetLayerOffset(Image, TargetMipLevel) * Layer;
+ }
+
+ int SrcLayerIndex = -1;
+
+ if (IsSrcLayered && Gpu.ResourceManager.TryGetTextureLayer(SrcKey, out SrcLayerIndex) && SrcLayerIndex != 0)
+ {
+ SrcKey = SrcKey - GetLayerOffset(SrcTexture, SrcLayerIndex);
+ }
+
+ int DstLayerIndex = -1;
+
+ if (IsDstLayered && Gpu.ResourceManager.TryGetTextureLayer(DstKey, out DstLayerIndex) && DstLayerIndex != 0)
+ {
+ DstKey = DstKey - GetLayerOffset(DstTexture, DstLayerIndex);
+ }
+
Gpu.ResourceManager.SendTexture(Vmm, SrcKey, SrcTexture);
Gpu.ResourceManager.SendTexture(Vmm, DstKey, DstTexture);
+ if (IsSrcLayered && SrcLayerIndex == -1)
+ {
+ for (int Layer = 0; Layer < SrcTexture.LayerCount; Layer++)
+ {
+ Gpu.ResourceManager.SetTextureArrayLayer(SrcKey + GetLayerOffset(SrcTexture, Layer), Layer);
+ }
+
+ SrcLayerIndex = 0;
+ }
+
+ if (IsDstLayered && DstLayerIndex == -1)
+ {
+ for (int Layer = 0; Layer < DstTexture.LayerCount; Layer++)
+ {
+ Gpu.ResourceManager.SetTextureArrayLayer(DstKey + GetLayerOffset(DstTexture, Layer), Layer);
+ }
+
+ DstLayerIndex = 0;
+ }
+
int SrcBlitX1 = (int)(SrcBlitX >> 32);
int SrcBlitY1 = (int)(SrcBlitY >> 32);
@@ -109,8 +187,12 @@ namespace Ryujinx.Graphics.Graphics3d
int SrcBlitY2 = (int)(SrcBlitY + DstBlitH * BlitDvDy >> 32);
Gpu.Renderer.RenderTarget.Copy(
+ SrcTexture,
+ DstTexture,
SrcKey,
DstKey,
+ SrcLayerIndex,
+ DstLayerIndex,
SrcBlitX1,
SrcBlitY1,
SrcBlitX2,
@@ -124,6 +206,8 @@ namespace Ryujinx.Graphics.Graphics3d
//the texture is modified by the guest, however it doesn't
//work when resources that the gpu can write to are copied,
//like framebuffers.
+
+ // FIXME: SUPPORT MULTILAYER CORRECTLY HERE (this will cause weird stuffs on the first layer)
ImageUtils.CopyTexture(
Vmm,
SrcTexture,
diff --git a/Ryujinx.Graphics/Graphics3d/NvGpuEngine2dReg.cs b/Ryujinx.Graphics/Graphics3d/NvGpuEngine2dReg.cs
index c1c0dba2..7747b5a3 100644
--- a/Ryujinx.Graphics/Graphics3d/NvGpuEngine2dReg.cs
+++ b/Ryujinx.Graphics/Graphics3d/NvGpuEngine2dReg.cs
@@ -11,6 +11,7 @@ namespace Ryujinx.Graphics.Graphics3d
DstWidth = 0x86,
DstHeight = 0x87,
DstAddress = 0x88,
+ DstAddressLow = 0x89,
SrcFormat = 0x8c,
SrcLinear = 0x8d,
SrcBlockDimensions = 0x8e,
@@ -20,6 +21,7 @@ namespace Ryujinx.Graphics.Graphics3d
SrcWidth = 0x92,
SrcHeight = 0x93,
SrcAddress = 0x94,
+ SrcAddressLow = 0x95,
ClipEnable = 0xa4,
CopyOperation = 0xab,
BlitControl = 0x223,
diff --git a/Ryujinx.Graphics/Graphics3d/NvGpuEngine3d.cs b/Ryujinx.Graphics/Graphics3d/NvGpuEngine3d.cs
index 6120053d..eb6289fb 100644
--- a/Ryujinx.Graphics/Graphics3d/NvGpuEngine3d.cs
+++ b/Ryujinx.Graphics/Graphics3d/NvGpuEngine3d.cs
@@ -1,4 +1,5 @@
using Ryujinx.Common;
+using Ryujinx.Common.Logging;
using Ryujinx.Graphics.Gal;
using Ryujinx.Graphics.Memory;
using Ryujinx.Graphics.Texture;
@@ -190,7 +191,11 @@ namespace Ryujinx.Graphics.Graphics3d
int Width = ReadRegister(NvGpuEngine3dReg.FrameBufferNWidth + FbIndex * 0x10);
int Height = ReadRegister(NvGpuEngine3dReg.FrameBufferNHeight + FbIndex * 0x10);
- int BlockDim = ReadRegister(NvGpuEngine3dReg.FrameBufferNBlockDim + FbIndex * 0x10);
+ int ArrayMode = ReadRegister(NvGpuEngine3dReg.FrameBufferNArrayMode + FbIndex * 0x10);
+ int LayerCount = ArrayMode & 0xFFFF;
+ int LayerStride = ReadRegister(NvGpuEngine3dReg.FrameBufferNLayerStride + FbIndex * 0x10);
+ int BaseLayer = ReadRegister(NvGpuEngine3dReg.FrameBufferNBaseLayer + FbIndex * 0x10);
+ int BlockDim = ReadRegister(NvGpuEngine3dReg.FrameBufferNBlockDim + FbIndex * 0x10);
int GobBlockHeight = 1 << ((BlockDim >> 4) & 7);
@@ -210,7 +215,7 @@ namespace Ryujinx.Graphics.Graphics3d
GalImageFormat Format = ImageUtils.ConvertSurface((GalSurfaceFormat)SurfFormat);
- GalImage Image = new GalImage(Width, Height, 1, GobBlockHeight, Layout, Format);
+ GalImage Image = new GalImage(Width, Height, 1, 1, 1, GobBlockHeight, 1, Layout, Format, GalTextureTarget.TwoD);
Gpu.ResourceManager.SendColorBuffer(Vmm, Key, FbIndex, Image);
@@ -264,7 +269,8 @@ namespace Ryujinx.Graphics.Graphics3d
GalImageFormat Format = ImageUtils.ConvertZeta((GalZetaFormat)ZetaFormat);
- GalImage Image = new GalImage(Width, Height, 1, GobBlockHeight, Layout, Format);
+ // TODO: Support non 2D?
+ GalImage Image = new GalImage(Width, Height, 1, 1, 1, GobBlockHeight, 1, Layout, Format, GalTextureTarget.TwoD);
Gpu.ResourceManager.SendZetaBuffer(Vmm, Key, Image);
}
@@ -600,7 +606,7 @@ namespace Ryujinx.Graphics.Graphics3d
}
Gpu.Renderer.Texture.Bind(Key, Index, Image);
- Gpu.Renderer.Texture.SetSampler(Sampler);
+ Gpu.Renderer.Texture.SetSampler(Image, Sampler);
}
}
diff --git a/Ryujinx.Graphics/Graphics3d/NvGpuEngine3dReg.cs b/Ryujinx.Graphics/Graphics3d/NvGpuEngine3dReg.cs
index 026b0cd1..91346464 100644
--- a/Ryujinx.Graphics/Graphics3d/NvGpuEngine3dReg.cs
+++ b/Ryujinx.Graphics/Graphics3d/NvGpuEngine3dReg.cs
@@ -2,112 +2,115 @@ namespace Ryujinx.Graphics.Graphics3d
{
enum NvGpuEngine3dReg
{
- FrameBufferNAddress = 0x200,
- FrameBufferNWidth = 0x202,
- FrameBufferNHeight = 0x203,
- FrameBufferNFormat = 0x204,
- FrameBufferNBlockDim = 0x205,
- ViewportNScaleX = 0x280,
- ViewportNScaleY = 0x281,
- ViewportNScaleZ = 0x282,
- ViewportNTranslateX = 0x283,
- ViewportNTranslateY = 0x284,
- ViewportNTranslateZ = 0x285,
- ViewportNHoriz = 0x300,
- ViewportNVert = 0x301,
- DepthRangeNNear = 0x302,
- DepthRangeNFar = 0x303,
- VertexArrayFirst = 0x35d,
- VertexArrayCount = 0x35e,
- ClearNColor = 0x360,
- ClearDepth = 0x364,
- ClearStencil = 0x368,
- ScissorEnable = 0x380,
- ScissorHorizontal = 0x381,
- ScissorVertical = 0x382,
- StencilBackFuncRef = 0x3d5,
- StencilBackMask = 0x3d6,
- StencilBackFuncMask = 0x3d7,
- ColorMaskCommon = 0x3e4,
- RTSeparateFragData = 0x3eb,
- ZetaAddress = 0x3f8,
- ZetaFormat = 0x3fa,
- ZetaBlockDimensions = 0x3fb,
- ZetaLayerStride = 0x3fc,
- VertexAttribNFormat = 0x458,
- RTControl = 0x487,
- ZetaHoriz = 0x48a,
- ZetaVert = 0x48b,
- ZetaArrayMode = 0x48c,
- LinkedTsc = 0x48d,
- DepthTestEnable = 0x4b3,
- BlendIndependent = 0x4b9,
- DepthWriteEnable = 0x4ba,
- DepthTestFunction = 0x4c3,
- BlendSeparateAlpha = 0x4cf,
- BlendEquationRgb = 0x4d0,
- BlendFuncSrcRgb = 0x4d1,
- BlendFuncDstRgb = 0x4d2,
- BlendEquationAlpha = 0x4d3,
- BlendFuncSrcAlpha = 0x4d4,
- BlendFuncDstAlpha = 0x4d6,
- BlendEnable = 0x4d7,
- IBlendNEnable = 0x4d8,
- StencilEnable = 0x4e0,
- StencilFrontOpFail = 0x4e1,
- StencilFrontOpZFail = 0x4e2,
- StencilFrontOpZPass = 0x4e3,
- StencilFrontFuncFunc = 0x4e4,
- StencilFrontFuncRef = 0x4e5,
- StencilFrontFuncMask = 0x4e6,
- StencilFrontMask = 0x4e7,
- ScreenYControl = 0x4eb,
- VertexArrayElemBase = 0x50d,
- VertexArrayInstBase = 0x50e,
- ZetaEnable = 0x54e,
- TexHeaderPoolOffset = 0x55d,
- TexSamplerPoolOffset = 0x557,
- StencilTwoSideEnable = 0x565,
- StencilBackOpFail = 0x566,
- StencilBackOpZFail = 0x567,
- StencilBackOpZPass = 0x568,
- StencilBackFuncFunc = 0x569,
- FrameBufferSrgb = 0x56e,
- ShaderAddress = 0x582,
- VertexBeginGl = 0x586,
- PrimRestartEnable = 0x591,
- PrimRestartIndex = 0x592,
- IndexArrayAddress = 0x5f2,
- IndexArrayEndAddr = 0x5f4,
- IndexArrayFormat = 0x5f6,
- IndexBatchFirst = 0x5f7,
- IndexBatchCount = 0x5f8,
- VertexArrayNInstance = 0x620,
- CullFaceEnable = 0x646,
- FrontFace = 0x647,
- CullFace = 0x648,
- ColorMaskN = 0x680,
- QueryAddress = 0x6c0,
- QuerySequence = 0x6c2,
- QueryControl = 0x6c3,
- VertexArrayNControl = 0x700,
- VertexArrayNAddress = 0x701,
- VertexArrayNDivisor = 0x703,
- IBlendNSeparateAlpha = 0x780,
- IBlendNEquationRgb = 0x781,
- IBlendNFuncSrcRgb = 0x782,
- IBlendNFuncDstRgb = 0x783,
- IBlendNEquationAlpha = 0x784,
- IBlendNFuncSrcAlpha = 0x785,
- IBlendNFuncDstAlpha = 0x786,
- VertexArrayNEndAddr = 0x7c0,
- ShaderNControl = 0x800,
- ShaderNOffset = 0x801,
- ShaderNMaxGprs = 0x803,
- ShaderNType = 0x804,
- ConstBufferSize = 0x8e0,
- ConstBufferAddress = 0x8e1,
- ConstBufferOffset = 0x8e3,
- TextureCbIndex = 0x982
+ FrameBufferNAddress = 0x200,
+ FrameBufferNWidth = 0x202,
+ FrameBufferNHeight = 0x203,
+ FrameBufferNFormat = 0x204,
+ FrameBufferNBlockDim = 0x205,
+ FrameBufferNArrayMode = 0x206,
+ FrameBufferNLayerStride = 0x207,
+ FrameBufferNBaseLayer = 0x208,
+ ViewportNScaleX = 0x280,
+ ViewportNScaleY = 0x281,
+ ViewportNScaleZ = 0x282,
+ ViewportNTranslateX = 0x283,
+ ViewportNTranslateY = 0x284,
+ ViewportNTranslateZ = 0x285,
+ ViewportNHoriz = 0x300,
+ ViewportNVert = 0x301,
+ DepthRangeNNear = 0x302,
+ DepthRangeNFar = 0x303,
+ VertexArrayFirst = 0x35d,
+ VertexArrayCount = 0x35e,
+ ClearNColor = 0x360,
+ ClearDepth = 0x364,
+ ClearStencil = 0x368,
+ ScissorEnable = 0x380,
+ ScissorHorizontal = 0x381,
+ ScissorVertical = 0x382,
+ StencilBackFuncRef = 0x3d5,
+ StencilBackMask = 0x3d6,
+ StencilBackFuncMask = 0x3d7,
+ ColorMaskCommon = 0x3e4,
+ RTSeparateFragData = 0x3eb,
+ ZetaAddress = 0x3f8,
+ ZetaFormat = 0x3fa,
+ ZetaBlockDimensions = 0x3fb,
+ ZetaLayerStride = 0x3fc,
+ VertexAttribNFormat = 0x458,
+ RTControl = 0x487,
+ ZetaHoriz = 0x48a,
+ ZetaVert = 0x48b,
+ ZetaArrayMode = 0x48c,
+ LinkedTsc = 0x48d,
+ DepthTestEnable = 0x4b3,
+ BlendIndependent = 0x4b9,
+ DepthWriteEnable = 0x4ba,
+ DepthTestFunction = 0x4c3,
+ BlendSeparateAlpha = 0x4cf,
+ BlendEquationRgb = 0x4d0,
+ BlendFuncSrcRgb = 0x4d1,
+ BlendFuncDstRgb = 0x4d2,
+ BlendEquationAlpha = 0x4d3,
+ BlendFuncSrcAlpha = 0x4d4,
+ BlendFuncDstAlpha = 0x4d6,
+ BlendEnable = 0x4d7,
+ IBlendNEnable = 0x4d8,
+ StencilEnable = 0x4e0,
+ StencilFrontOpFail = 0x4e1,
+ StencilFrontOpZFail = 0x4e2,
+ StencilFrontOpZPass = 0x4e3,
+ StencilFrontFuncFunc = 0x4e4,
+ StencilFrontFuncRef = 0x4e5,
+ StencilFrontFuncMask = 0x4e6,
+ StencilFrontMask = 0x4e7,
+ ScreenYControl = 0x4eb,
+ VertexArrayElemBase = 0x50d,
+ VertexArrayInstBase = 0x50e,
+ ZetaEnable = 0x54e,
+ TexHeaderPoolOffset = 0x55d,
+ TexSamplerPoolOffset = 0x557,
+ StencilTwoSideEnable = 0x565,
+ StencilBackOpFail = 0x566,
+ StencilBackOpZFail = 0x567,
+ StencilBackOpZPass = 0x568,
+ StencilBackFuncFunc = 0x569,
+ FrameBufferSrgb = 0x56e,
+ ShaderAddress = 0x582,
+ VertexBeginGl = 0x586,
+ PrimRestartEnable = 0x591,
+ PrimRestartIndex = 0x592,
+ IndexArrayAddress = 0x5f2,
+ IndexArrayEndAddr = 0x5f4,
+ IndexArrayFormat = 0x5f6,
+ IndexBatchFirst = 0x5f7,
+ IndexBatchCount = 0x5f8,
+ VertexArrayNInstance = 0x620,
+ CullFaceEnable = 0x646,
+ FrontFace = 0x647,
+ CullFace = 0x648,
+ ColorMaskN = 0x680,
+ QueryAddress = 0x6c0,
+ QuerySequence = 0x6c2,
+ QueryControl = 0x6c3,
+ VertexArrayNControl = 0x700,
+ VertexArrayNAddress = 0x701,
+ VertexArrayNDivisor = 0x703,
+ IBlendNSeparateAlpha = 0x780,
+ IBlendNEquationRgb = 0x781,
+ IBlendNFuncSrcRgb = 0x782,
+ IBlendNFuncDstRgb = 0x783,
+ IBlendNEquationAlpha = 0x784,
+ IBlendNFuncSrcAlpha = 0x785,
+ IBlendNFuncDstAlpha = 0x786,
+ VertexArrayNEndAddr = 0x7c0,
+ ShaderNControl = 0x800,
+ ShaderNOffset = 0x801,
+ ShaderNMaxGprs = 0x803,
+ ShaderNType = 0x804,
+ ConstBufferSize = 0x8e0,
+ ConstBufferAddress = 0x8e1,
+ ConstBufferOffset = 0x8e3,
+ TextureCbIndex = 0x982
}
} \ No newline at end of file
diff --git a/Ryujinx.Graphics/Graphics3d/NvGpuEngineM2mf.cs b/Ryujinx.Graphics/Graphics3d/NvGpuEngineM2mf.cs
index d89059c0..2f1df3d3 100644
--- a/Ryujinx.Graphics/Graphics3d/NvGpuEngineM2mf.cs
+++ b/Ryujinx.Graphics/Graphics3d/NvGpuEngineM2mf.cs
@@ -1,3 +1,4 @@
+using Ryujinx.Common.Logging;
using Ryujinx.Graphics.Memory;
using Ryujinx.Graphics.Texture;
using System.Collections.Generic;
@@ -125,29 +126,37 @@ namespace Ryujinx.Graphics.Graphics3d
if (SrcLinear)
{
- SrcSwizzle = new LinearSwizzle(SrcPitch, SrcCpp);
+ SrcSwizzle = new LinearSwizzle(SrcPitch, SrcCpp, SrcSizeX, SrcSizeY);
}
else
{
- SrcSwizzle = new BlockLinearSwizzle(SrcSizeX, SrcCpp, SrcBlockHeight);
+ SrcSwizzle = new BlockLinearSwizzle(
+ SrcSizeX,
+ SrcSizeY, 1,
+ SrcBlockHeight, 1,
+ SrcCpp);
}
ISwizzle DstSwizzle;
if (DstLinear)
{
- DstSwizzle = new LinearSwizzle(DstPitch, DstCpp);
+ DstSwizzle = new LinearSwizzle(DstPitch, DstCpp, SrcSizeX, SrcSizeY);
}
else
{
- DstSwizzle = new BlockLinearSwizzle(DstSizeX, DstCpp, DstBlockHeight);
+ DstSwizzle = new BlockLinearSwizzle(
+ DstSizeX,
+ DstSizeY, 1,
+ DstBlockHeight, 1,
+ DstCpp);
}
for (int Y = 0; Y < YCount; Y++)
for (int X = 0; X < XCount; X++)
{
- int SrcOffset = SrcSwizzle.GetSwizzleOffset(SrcPosX + X, SrcPosY + Y);
- int DstOffset = DstSwizzle.GetSwizzleOffset(DstPosX + X, DstPosY + Y);
+ int SrcOffset = SrcSwizzle.GetSwizzleOffset(SrcPosX + X, SrcPosY + Y, 0);
+ int DstOffset = DstSwizzle.GetSwizzleOffset(DstPosX + X, DstPosY + Y, 0);
long Src = SrcPA + (uint)SrcOffset;
long Dst = DstPA + (uint)DstOffset;
diff --git a/Ryujinx.Graphics/Graphics3d/NvGpuEngineP2mf.cs b/Ryujinx.Graphics/Graphics3d/NvGpuEngineP2mf.cs
index 68155255..62872ba1 100644
--- a/Ryujinx.Graphics/Graphics3d/NvGpuEngineP2mf.cs
+++ b/Ryujinx.Graphics/Graphics3d/NvGpuEngineP2mf.cs
@@ -1,3 +1,4 @@
+using Ryujinx.Common.Logging;
using Ryujinx.Graphics.Memory;
using Ryujinx.Graphics.Texture;
using System.Collections.Generic;
@@ -119,14 +120,17 @@ namespace Ryujinx.Graphics.Graphics3d
}
else
{
- BlockLinearSwizzle Swizzle = new BlockLinearSwizzle(CopyWidth, 1, CopyGobBlockHeight);
+ BlockLinearSwizzle Swizzle = new BlockLinearSwizzle(
+ CopyWidth,
+ CopyHeight, 1,
+ CopyGobBlockHeight, 1, 1);
int SrcOffset = 0;
for (int Y = CopyStartY; Y < CopyHeight && SrcOffset < CopySize; Y++)
for (int X = CopyStartX; X < CopyWidth && SrcOffset < CopySize; X++)
{
- int DstOffset = Swizzle.GetSwizzleOffset(X, Y);
+ int DstOffset = Swizzle.GetSwizzleOffset(X, Y, 0);
Vmm.WriteByte(CopyAddress + DstOffset, Buffer[SrcOffset++]);
}
diff --git a/Ryujinx.Graphics/Graphics3d/Texture/ASTCDecoder.cs b/Ryujinx.Graphics/Graphics3d/Texture/ASTCDecoder.cs
index 1efa0255..00158dc1 100644
--- a/Ryujinx.Graphics/Graphics3d/Texture/ASTCDecoder.cs
+++ b/Ryujinx.Graphics/Graphics3d/Texture/ASTCDecoder.cs
@@ -72,6 +72,7 @@ namespace Ryujinx.Graphics.Texture
if (BlockZ != 1 || Z != 1)
{
+ // TODO: Support 3D textures?
throw new ASTCDecoderException("3D compressed textures unsupported!");
}
diff --git a/Ryujinx.Graphics/Graphics3d/Texture/BlockLinearSwizzle.cs b/Ryujinx.Graphics/Graphics3d/Texture/BlockLinearSwizzle.cs
index 9451291e..1be06442 100644
--- a/Ryujinx.Graphics/Graphics3d/Texture/BlockLinearSwizzle.cs
+++ b/Ryujinx.Graphics/Graphics3d/Texture/BlockLinearSwizzle.cs
@@ -1,51 +1,178 @@
+using Ryujinx.Common;
using System;
namespace Ryujinx.Graphics.Texture
{
class BlockLinearSwizzle : ISwizzle
{
+ private const int GobWidth = 64;
+ private const int GobHeight = 8;
+
+ private const int GobSize = GobWidth * GobHeight;
+
+ private int TexWidth;
+ private int TexHeight;
+ private int TexDepth;
+ private int TexGobBlockHeight;
+ private int TexGobBlockDepth;
+ private int TexBpp;
+
+ private int BhMask;
+ private int BdMask;
+
private int BhShift;
+ private int BdShift;
private int BppShift;
- private int BhMask;
private int XShift;
- private int GobStride;
- public BlockLinearSwizzle(int Width, int Bpp, int BlockHeight = 16)
+ private int RobSize;
+ private int SliceSize;
+
+ private int BaseOffset;
+
+ public BlockLinearSwizzle(
+ int Width,
+ int Height,
+ int Depth,
+ int GobBlockHeight,
+ int GobBlockDepth,
+ int Bpp)
{
- BhMask = (BlockHeight * 8) - 1;
+ TexWidth = Width;
+ TexHeight = Height;
+ TexDepth = Depth;
+ TexGobBlockHeight = GobBlockHeight;
+ TexGobBlockDepth = GobBlockDepth;
+ TexBpp = Bpp;
+
+ BppShift = BitUtils.CountTrailingZeros32(Bpp);
+
+ SetMipLevel(0);
+ }
+
+ public void SetMipLevel(int Level)
+ {
+ BaseOffset = GetMipOffset(Level);
+
+ int Width = Math.Max(1, TexWidth >> Level);
+ int Height = Math.Max(1, TexHeight >> Level);
+ int Depth = Math.Max(1, TexDepth >> Level);
- BhShift = CountLsbZeros(BlockHeight * 8);
- BppShift = CountLsbZeros(Bpp);
+ GobBlockSizes GbSizes = AdjustGobBlockSizes(Height, Depth);
- int WidthInGobs = (int)MathF.Ceiling(Width * Bpp / 64f);
+ BhMask = GbSizes.Height - 1;
+ BdMask = GbSizes.Depth - 1;
- GobStride = 512 * BlockHeight * WidthInGobs;
+ BhShift = BitUtils.CountTrailingZeros32(GbSizes.Height);
+ BdShift = BitUtils.CountTrailingZeros32(GbSizes.Depth);
- XShift = CountLsbZeros(512 * BlockHeight);
+ XShift = BitUtils.CountTrailingZeros32(GobSize * GbSizes.Height * GbSizes.Depth);
+
+ RobAndSliceSizes GsSizes = GetRobAndSliceSizes(Width, Height, GbSizes);
+
+ RobSize = GsSizes.RobSize;
+ SliceSize = GsSizes.SliceSize;
+ }
+
+ public int GetImageSize(int MipsCount)
+ {
+ int Size = GetMipOffset(MipsCount);
+
+ Size = (Size + 0x1fff) & ~0x1fff;
+
+ return Size;
}
- private int CountLsbZeros(int Value)
+ public int GetMipOffset(int Level)
{
- int Count = 0;
+ int TotalSize = 0;
- while (((Value >> Count) & 1) == 0)
+ for (int Index = 0; Index < Level; Index++)
{
- Count++;
+ int Width = Math.Max(1, TexWidth >> Index);
+ int Height = Math.Max(1, TexHeight >> Index);
+ int Depth = Math.Max(1, TexDepth >> Index);
+
+ GobBlockSizes GbSizes = AdjustGobBlockSizes(Height, Depth);
+
+ RobAndSliceSizes RsSizes = GetRobAndSliceSizes(Width, Height, GbSizes);
+
+ TotalSize += BitUtils.DivRoundUp(Depth, GbSizes.Depth) * RsSizes.SliceSize;
}
- return Count;
+ return TotalSize;
}
- public int GetSwizzleOffset(int X, int Y)
+ private struct GobBlockSizes
+ {
+ public int Height;
+ public int Depth;
+
+ public GobBlockSizes(int GobBlockHeight, int GobBlockDepth)
+ {
+ this.Height = GobBlockHeight;
+ this.Depth = GobBlockDepth;
+ }
+ }
+
+ private GobBlockSizes AdjustGobBlockSizes(int Height, int Depth)
+ {
+ int GobBlockHeight = TexGobBlockHeight;
+ int GobBlockDepth = TexGobBlockDepth;
+
+ int Pow2Height = BitUtils.Pow2RoundUp(Height);
+ int Pow2Depth = BitUtils.Pow2RoundUp(Depth);
+
+ while (GobBlockHeight * GobHeight > Pow2Height && GobBlockHeight > 1)
+ {
+ GobBlockHeight >>= 1;
+ }
+
+ while (GobBlockDepth > Pow2Depth && GobBlockDepth > 1)
+ {
+ GobBlockDepth >>= 1;
+ }
+
+ return new GobBlockSizes(GobBlockHeight, GobBlockDepth);
+ }
+
+ private struct RobAndSliceSizes
+ {
+ public int RobSize;
+ public int SliceSize;
+
+ public RobAndSliceSizes(int RobSize, int SliceSize)
+ {
+ this.RobSize = RobSize;
+ this.SliceSize = SliceSize;
+ }
+ }
+
+ private RobAndSliceSizes GetRobAndSliceSizes(int Width, int Height, GobBlockSizes GbSizes)
+ {
+ int WidthInGobs = BitUtils.DivRoundUp(Width * TexBpp, GobWidth);
+
+ int RobSize = GobSize * GbSizes.Height * GbSizes.Depth * WidthInGobs;
+
+ int SliceSize = BitUtils.DivRoundUp(Height, GbSizes.Height * GobHeight) * RobSize;
+
+ return new RobAndSliceSizes(RobSize, SliceSize);
+ }
+
+ public int GetSwizzleOffset(int X, int Y, int Z)
{
X <<= BppShift;
- int Position = (Y >> BhShift) * GobStride;
+ int YH = Y / GobHeight;
+
+ int Position = (Z >> BdShift) * SliceSize + (YH >> BhShift) * RobSize;
+
+ Position += (X / GobWidth) << XShift;
- Position += (X >> 6) << XShift;
+ Position += (YH & BhMask) * GobSize;
- Position += ((Y & BhMask) >> 3) << 9;
+ Position += ((Z & BdMask) * GobSize) << BhShift;
Position += ((X & 0x3f) >> 5) << 8;
Position += ((Y & 0x07) >> 1) << 6;
@@ -53,7 +180,7 @@ namespace Ryujinx.Graphics.Texture
Position += ((Y & 0x01) >> 0) << 4;
Position += ((X & 0x0f) >> 0) << 0;
- return Position;
+ return BaseOffset + Position;
}
}
} \ No newline at end of file
diff --git a/Ryujinx.Graphics/Graphics3d/Texture/ISwizzle.cs b/Ryujinx.Graphics/Graphics3d/Texture/ISwizzle.cs
index 583fc20c..2e0e8aed 100644
--- a/Ryujinx.Graphics/Graphics3d/Texture/ISwizzle.cs
+++ b/Ryujinx.Graphics/Graphics3d/Texture/ISwizzle.cs
@@ -2,6 +2,12 @@ namespace Ryujinx.Graphics.Texture
{
interface ISwizzle
{
- int GetSwizzleOffset(int X, int Y);
+ int GetSwizzleOffset(int X, int Y, int Z);
+
+ void SetMipLevel(int Level);
+
+ int GetMipOffset(int Level);
+
+ int GetImageSize(int MipsCount);
}
} \ No newline at end of file
diff --git a/Ryujinx.Graphics/Graphics3d/Texture/ImageUtils.cs b/Ryujinx.Graphics/Graphics3d/Texture/ImageUtils.cs
index f958e1de..c4208935 100644
--- a/Ryujinx.Graphics/Graphics3d/Texture/ImageUtils.cs
+++ b/Ryujinx.Graphics/Graphics3d/Texture/ImageUtils.cs
@@ -1,4 +1,6 @@
using ChocolArm64.Memory;
+using OpenTK.Graphics.OpenGL;
+using Ryujinx.Common;
using Ryujinx.Graphics.Gal;
using Ryujinx.Graphics.Memory;
using System;
@@ -23,14 +25,16 @@ namespace Ryujinx.Graphics.Texture
public int BytesPerPixel { get; private set; }
public int BlockWidth { get; private set; }
public int BlockHeight { get; private set; }
+ public int BlockDepth { get; private set; }
public TargetBuffer Target { get; private set; }
- public ImageDescriptor(int BytesPerPixel, int BlockWidth, int BlockHeight, TargetBuffer Target)
+ public ImageDescriptor(int BytesPerPixel, int BlockWidth, int BlockHeight, int BlockDepth, TargetBuffer Target)
{
this.BytesPerPixel = BytesPerPixel;
this.BlockWidth = BlockWidth;
this.BlockHeight = BlockHeight;
+ this.BlockDepth = BlockDepth;
this.Target = Target;
}
}
@@ -92,52 +96,52 @@ namespace Ryujinx.Graphics.Texture
private static readonly Dictionary<GalImageFormat, ImageDescriptor> s_ImageTable =
new Dictionary<GalImageFormat, ImageDescriptor>()
{
- { GalImageFormat.RGBA32, new ImageDescriptor(16, 1, 1, TargetBuffer.Color) },
- { GalImageFormat.RGBA16, new ImageDescriptor(8, 1, 1, TargetBuffer.Color) },
- { GalImageFormat.RG32, new ImageDescriptor(8, 1, 1, TargetBuffer.Color) },
- { GalImageFormat.RGBX8, new ImageDescriptor(4, 1, 1, TargetBuffer.Color) },
- { GalImageFormat.RGBA8, new ImageDescriptor(4, 1, 1, TargetBuffer.Color) },
- { GalImageFormat.BGRA8, new ImageDescriptor(4, 1, 1, TargetBuffer.Color) },
- { GalImageFormat.RGB10A2, new ImageDescriptor(4, 1, 1, TargetBuffer.Color) },
- { GalImageFormat.R32, new ImageDescriptor(4, 1, 1, TargetBuffer.Color) },
- { GalImageFormat.RGBA4, new ImageDescriptor(2, 1, 1, TargetBuffer.Color) },
- { GalImageFormat.BptcSfloat, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) },
- { GalImageFormat.BptcUfloat, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) },
- { GalImageFormat.BGR5A1, new ImageDescriptor(2, 1, 1, TargetBuffer.Color) },
- { GalImageFormat.RGB5A1, new ImageDescriptor(2, 1, 1, TargetBuffer.Color) },
- { GalImageFormat.RGB565, new ImageDescriptor(2, 1, 1, TargetBuffer.Color) },
- { GalImageFormat.BGR565, new ImageDescriptor(2, 1, 1, TargetBuffer.Color) },
- { GalImageFormat.BptcUnorm, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) },
- { GalImageFormat.RG16, new ImageDescriptor(4, 1, 1, TargetBuffer.Color) },
- { GalImageFormat.RG8, new ImageDescriptor(2, 1, 1, TargetBuffer.Color) },
- { GalImageFormat.R16, new ImageDescriptor(2, 1, 1, TargetBuffer.Color) },
- { GalImageFormat.R8, new ImageDescriptor(1, 1, 1, TargetBuffer.Color) },
- { GalImageFormat.R11G11B10, new ImageDescriptor(4, 1, 1, TargetBuffer.Color) },
- { GalImageFormat.BC1, new ImageDescriptor(8, 4, 4, TargetBuffer.Color) },
- { GalImageFormat.BC2, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) },
- { GalImageFormat.BC3, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) },
- { GalImageFormat.BC4, new ImageDescriptor(8, 4, 4, TargetBuffer.Color) },
- { GalImageFormat.BC5, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) },
- { GalImageFormat.Astc2D4x4, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) },
- { GalImageFormat.Astc2D5x5, new ImageDescriptor(16, 5, 5, TargetBuffer.Color) },
- { GalImageFormat.Astc2D6x6, new ImageDescriptor(16, 6, 6, TargetBuffer.Color) },
- { GalImageFormat.Astc2D8x8, new ImageDescriptor(16, 8, 8, TargetBuffer.Color) },
- { GalImageFormat.Astc2D10x10, new ImageDescriptor(16, 10, 10, TargetBuffer.Color) },
- { GalImageFormat.Astc2D12x12, new ImageDescriptor(16, 12, 12, TargetBuffer.Color) },
- { GalImageFormat.Astc2D5x4, new ImageDescriptor(16, 5, 4, TargetBuffer.Color) },
- { GalImageFormat.Astc2D6x5, new ImageDescriptor(16, 6, 5, TargetBuffer.Color) },
- { GalImageFormat.Astc2D8x6, new ImageDescriptor(16, 8, 6, TargetBuffer.Color) },
- { GalImageFormat.Astc2D10x8, new ImageDescriptor(16, 10, 8, TargetBuffer.Color) },
- { GalImageFormat.Astc2D12x10, new ImageDescriptor(16, 12, 10, TargetBuffer.Color) },
- { GalImageFormat.Astc2D8x5, new ImageDescriptor(16, 8, 5, TargetBuffer.Color) },
- { GalImageFormat.Astc2D10x5, new ImageDescriptor(16, 10, 5, TargetBuffer.Color) },
- { GalImageFormat.Astc2D10x6, new ImageDescriptor(16, 10, 6, TargetBuffer.Color) },
-
- { GalImageFormat.D16, new ImageDescriptor(2, 1, 1, TargetBuffer.Depth) },
- { GalImageFormat.D24, new ImageDescriptor(4, 1, 1, TargetBuffer.Depth) },
- { GalImageFormat.D24S8, new ImageDescriptor(4, 1, 1, TargetBuffer.DepthStencil) },
- { GalImageFormat.D32, new ImageDescriptor(4, 1, 1, TargetBuffer.Depth) },
- { GalImageFormat.D32S8, new ImageDescriptor(8, 1, 1, TargetBuffer.DepthStencil) }
+ { GalImageFormat.RGBA32, new ImageDescriptor(16, 1, 1, 1, TargetBuffer.Color) },
+ { GalImageFormat.RGBA16, new ImageDescriptor(8, 1, 1, 1, TargetBuffer.Color) },
+ { GalImageFormat.RG32, new ImageDescriptor(8, 1, 1, 1, TargetBuffer.Color) },
+ { GalImageFormat.RGBX8, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) },
+ { GalImageFormat.RGBA8, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) },
+ { GalImageFormat.BGRA8, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) },
+ { GalImageFormat.RGB10A2, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) },
+ { GalImageFormat.R32, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) },
+ { GalImageFormat.RGBA4, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) },
+ { GalImageFormat.BptcSfloat, new ImageDescriptor(16, 4, 4, 1, TargetBuffer.Color) },
+ { GalImageFormat.BptcUfloat, new ImageDescriptor(16, 4, 4, 1, TargetBuffer.Color) },
+ { GalImageFormat.BGR5A1, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) },
+ { GalImageFormat.RGB5A1, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) },
+ { GalImageFormat.RGB565, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) },
+ { GalImageFormat.BGR565, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) },
+ { GalImageFormat.BptcUnorm, new ImageDescriptor(16, 4, 4, 1, TargetBuffer.Color) },
+ { GalImageFormat.RG16, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) },
+ { GalImageFormat.RG8, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) },
+ { GalImageFormat.R16, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) },
+ { GalImageFormat.R8, new ImageDescriptor(1, 1, 1, 1, TargetBuffer.Color) },
+ { GalImageFormat.R11G11B10, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) },
+ { GalImageFormat.BC1, new ImageDescriptor(8, 4, 4, 1, TargetBuffer.Color) },
+ { GalImageFormat.BC2, new ImageDescriptor(16, 4, 4, 1, TargetBuffer.Color) },
+ { GalImageFormat.BC3, new ImageDescriptor(16, 4, 4, 1, TargetBuffer.Color) },
+ { GalImageFormat.BC4, new ImageDescriptor(8, 4, 4, 1, TargetBuffer.Color) },
+ { GalImageFormat.BC5, new ImageDescriptor(16, 4, 4, 1, TargetBuffer.Color) },
+ { GalImageFormat.Astc2D4x4, new ImageDescriptor(16, 4, 4, 1, TargetBuffer.Color) },
+ { GalImageFormat.Astc2D5x5, new ImageDescriptor(16, 5, 5, 1, TargetBuffer.Color) },
+ { GalImageFormat.Astc2D6x6, new ImageDescriptor(16, 6, 6, 1, TargetBuffer.Color) },
+ { GalImageFormat.Astc2D8x8, new ImageDescriptor(16, 8, 8, 1, TargetBuffer.Color) },
+ { GalImageFormat.Astc2D10x10, new ImageDescriptor(16, 10, 10, 1, TargetBuffer.Color) },
+ { GalImageFormat.Astc2D12x12, new ImageDescriptor(16, 12, 12, 1, TargetBuffer.Color) },
+ { GalImageFormat.Astc2D5x4, new ImageDescriptor(16, 5, 4, 1, TargetBuffer.Color) },
+ { GalImageFormat.Astc2D6x5, new ImageDescriptor(16, 6, 5, 1, TargetBuffer.Color) },
+ { GalImageFormat.Astc2D8x6, new ImageDescriptor(16, 8, 6, 1, TargetBuffer.Color) },
+ { GalImageFormat.Astc2D10x8, new ImageDescriptor(16, 10, 8, 1, TargetBuffer.Color) },
+ { GalImageFormat.Astc2D12x10, new ImageDescriptor(16, 12, 10, 1, TargetBuffer.Color) },
+ { GalImageFormat.Astc2D8x5, new ImageDescriptor(16, 8, 5, 1, TargetBuffer.Color) },
+ { GalImageFormat.Astc2D10x5, new ImageDescriptor(16, 10, 5, 1, TargetBuffer.Color) },
+ { GalImageFormat.Astc2D10x6, new ImageDescriptor(16, 10, 6, 1, TargetBuffer.Color) },
+
+ { GalImageFormat.D16, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Depth) },
+ { GalImageFormat.D24, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Depth) },
+ { GalImageFormat.D24S8, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.DepthStencil) },
+ { GalImageFormat.D32, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Depth) },
+ { GalImageFormat.D32S8, new ImageDescriptor(8, 1, 1, 1, TargetBuffer.DepthStencil) }
};
public static GalImageFormat ConvertTexture(
@@ -241,26 +245,37 @@ namespace Ryujinx.Graphics.Texture
ImageDescriptor Desc = GetImageDescriptor(Image.Format);
- (int Width, int Height) = GetImageSizeInBlocks(Image);
+ (int Width, int Height, int Depth) = GetImageSizeInBlocks(Image);
int BytesPerPixel = Desc.BytesPerPixel;
//Note: Each row of the texture needs to be aligned to 4 bytes.
int Pitch = (Width * BytesPerPixel + 3) & ~3;
- byte[] Data = new byte[Height * Pitch];
- for (int Y = 0; Y < Height; Y++)
- {
- int OutOffs = Y * Pitch;
+ int DataLayerSize = Height * Pitch * Depth;
+ byte[] Data = new byte[DataLayerSize * Image.LayerCount];
+
+ int TargetMipLevel = Image.MaxMipmapLevel <= 1 ? 1 : Image.MaxMipmapLevel - 1;
+ int LayerOffset = ImageUtils.GetLayerOffset(Image, TargetMipLevel);
- for (int X = 0; X < Width; X++)
+ for (int Layer = 0; Layer < Image.LayerCount; Layer++)
+ {
+ for (int Z = 0; Z < Depth; Z++)
{
- long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
+ for (int Y = 0; Y < Height; Y++)
+ {
+ int OutOffs = (DataLayerSize * Layer) + Y * Pitch + (Z * Width * Height * BytesPerPixel);
+
+ for (int X = 0; X < Width; X++)
+ {
+ long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y, Z);
- CpuMemory.ReadBytes(Position + Offset, Data, OutOffs, BytesPerPixel);
+ CpuMemory.ReadBytes(Position + (LayerOffset * Layer) + Offset, Data, OutOffs, BytesPerPixel);
- OutOffs += BytesPerPixel;
+ OutOffs += BytesPerPixel;
+ }
+ }
}
}
@@ -273,16 +288,17 @@ namespace Ryujinx.Graphics.Texture
ImageDescriptor Desc = GetImageDescriptor(Image.Format);
- (int Width, int Height) = ImageUtils.GetImageSizeInBlocks(Image);
+ (int Width, int Height, int Depth) = ImageUtils.GetImageSizeInBlocks(Image);
int BytesPerPixel = Desc.BytesPerPixel;
int InOffs = 0;
+ for (int Z = 0; Z < Depth; Z++)
for (int Y = 0; Y < Height; Y++)
for (int X = 0; X < Width; X++)
{
- long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
+ long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y, Z);
Vmm.Memory.WriteBytes(Position + Offset, Data, InOffs, BytesPerPixel);
@@ -290,6 +306,7 @@ namespace Ryujinx.Graphics.Texture
}
}
+ // TODO: Support non 2D
public static bool CopyTexture(
NvGpuVmm Vmm,
GalImage SrcImage,
@@ -318,8 +335,8 @@ namespace Ryujinx.Graphics.Texture
for (int Y = 0; Y < Height; Y++)
for (int X = 0; X < Width; X++)
{
- long SrcOffset = (uint)SrcSwizzle.GetSwizzleOffset(SrcX + X, SrcY + Y);
- long DstOffset = (uint)DstSwizzle.GetSwizzleOffset(DstX + X, DstY + Y);
+ long SrcOffset = (uint)SrcSwizzle.GetSwizzleOffset(SrcX + X, SrcY + Y, 0);
+ long DstOffset = (uint)DstSwizzle.GetSwizzleOffset(DstX + X, DstY + Y, 0);
byte[] Texel = Vmm.ReadBytes(SrcAddress + SrcOffset, BytesPerPixel);
@@ -333,10 +350,41 @@ namespace Ryujinx.Graphics.Texture
{
ImageDescriptor Desc = GetImageDescriptor(Image.Format);
+ int ComponentCount = GetCoordsCountTextureTarget(Image.TextureTarget);
+
+ if (IsArray(Image.TextureTarget))
+ ComponentCount--;
+
int Width = DivRoundUp(Image.Width, Desc.BlockWidth);
int Height = DivRoundUp(Image.Height, Desc.BlockHeight);
+ int Depth = DivRoundUp(Image.Depth, Desc.BlockDepth);
+
+ switch (ComponentCount)
+ {
+ case 1:
+ return Desc.BytesPerPixel * Width * Image.LayerCount;
+ case 2:
+ return Desc.BytesPerPixel * Width * Height * Image.LayerCount;
+ case 3:
+ return Desc.BytesPerPixel * Width * Height * Depth * Image.LayerCount;
+ default:
+ throw new InvalidOperationException($"Invalid component count: {ComponentCount}");
+ }
+ }
+
+ public static int GetGpuSize(GalImage Image, bool forcePitch = false)
+ {
+ return TextureHelper.GetSwizzle(Image).GetImageSize(Image.MaxMipmapLevel) * Image.LayerCount;
+ }
+
+ public static int GetLayerOffset(GalImage Image, int MipLevel)
+ {
+ if (MipLevel <= 0)
+ {
+ MipLevel = 1;
+ }
- return Desc.BytesPerPixel * Width * Height;
+ return TextureHelper.GetSwizzle(Image).GetMipOffset(MipLevel);
}
public static int GetPitch(GalImageFormat Format, int Width)
@@ -360,6 +408,11 @@ namespace Ryujinx.Graphics.Texture
return GetImageDescriptor(Format).BlockHeight;
}
+ public static int GetBlockDepth(GalImageFormat Format)
+ {
+ return GetImageDescriptor(Format).BlockDepth;
+ }
+
public static int GetAlignedWidth(GalImage Image)
{
ImageDescriptor Desc = GetImageDescriptor(Image.Format);
@@ -378,12 +431,13 @@ namespace Ryujinx.Graphics.Texture
return (Image.Width + AlignMask) & ~AlignMask;
}
- public static (int Width, int Height) GetImageSizeInBlocks(GalImage Image)
+ public static (int Width, int Height, int Depth) GetImageSizeInBlocks(GalImage Image)
{
ImageDescriptor Desc = GetImageDescriptor(Image.Format);
return (DivRoundUp(Image.Width, Desc.BlockWidth),
- DivRoundUp(Image.Height, Desc.BlockHeight));
+ DivRoundUp(Image.Height, Desc.BlockHeight),
+ DivRoundUp(Image.Depth, Desc.BlockDepth));
}
public static int GetBytesPerPixel(GalImageFormat Format)
@@ -443,5 +497,66 @@ namespace Ryujinx.Graphics.Texture
default: throw new NotImplementedException(((int)Type).ToString());
}
}
+
+ public static TextureTarget GetTextureTarget(GalTextureTarget GalTextureTarget)
+ {
+ switch (GalTextureTarget)
+ {
+ case GalTextureTarget.OneD:
+ return TextureTarget.Texture1D;
+ case GalTextureTarget.TwoD:
+ case GalTextureTarget.TwoDNoMipMap:
+ return TextureTarget.Texture2D;
+ case GalTextureTarget.ThreeD:
+ return TextureTarget.Texture3D;
+ case GalTextureTarget.OneDArray:
+ return TextureTarget.Texture1DArray;
+ case GalTextureTarget.OneDBuffer:
+ return TextureTarget.TextureBuffer;
+ case GalTextureTarget.TwoDArray:
+ return TextureTarget.Texture2DArray;
+ case GalTextureTarget.CubeMap:
+ return TextureTarget.TextureCubeMap;
+ case GalTextureTarget.CubeArray:
+ return TextureTarget.TextureCubeMapArray;
+ default:
+ throw new NotSupportedException($"Texture target {GalTextureTarget} currently not supported!");
+ }
+ }
+
+ public static bool IsArray(GalTextureTarget TextureTarget)
+ {
+ switch (TextureTarget)
+ {
+ case GalTextureTarget.OneDArray:
+ case GalTextureTarget.TwoDArray:
+ case GalTextureTarget.CubeArray:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public static int GetCoordsCountTextureTarget(GalTextureTarget TextureTarget)
+ {
+ switch (TextureTarget)
+ {
+ case GalTextureTarget.OneD:
+ return 1;
+ case GalTextureTarget.OneDArray:
+ case GalTextureTarget.OneDBuffer:
+ case GalTextureTarget.TwoD:
+ case GalTextureTarget.TwoDNoMipMap:
+ return 2;
+ case GalTextureTarget.ThreeD:
+ case GalTextureTarget.TwoDArray:
+ case GalTextureTarget.CubeMap:
+ return 3;
+ case GalTextureTarget.CubeArray:
+ return 4;
+ default:
+ throw new NotImplementedException($"TextureTarget.{TextureTarget} not implemented yet.");
+ }
+ }
}
}
diff --git a/Ryujinx.Graphics/Graphics3d/Texture/LinearSwizzle.cs b/Ryujinx.Graphics/Graphics3d/Texture/LinearSwizzle.cs
index ef468e27..e6509baa 100644
--- a/Ryujinx.Graphics/Graphics3d/Texture/LinearSwizzle.cs
+++ b/Ryujinx.Graphics/Graphics3d/Texture/LinearSwizzle.cs
@@ -1,3 +1,5 @@
+using System;
+
namespace Ryujinx.Graphics.Texture
{
class LinearSwizzle : ISwizzle
@@ -5,15 +7,39 @@ namespace Ryujinx.Graphics.Texture
private int Pitch;
private int Bpp;
- public LinearSwizzle(int Pitch, int Bpp)
+ private int SliceSize;
+
+ public LinearSwizzle(int Pitch, int Bpp, int Width, int Height)
{
- this.Pitch = Pitch;
- this.Bpp = Bpp;
+ this.Pitch = Pitch;
+ this.Bpp = Bpp;
+ SliceSize = Width * Height * Bpp;
+ }
+
+ public void SetMipLevel(int Level)
+ {
+ throw new NotImplementedException();
+ }
+
+ public int GetMipOffset(int Level)
+ {
+ if (Level == 1)
+ return SliceSize;
+ throw new NotImplementedException();
+ }
+
+ public int GetImageSize(int MipsCount)
+ {
+ int Size = GetMipOffset(MipsCount);
+
+ Size = (Size + 0x1fff) & ~0x1fff;
+
+ return Size;
}
- public int GetSwizzleOffset(int X, int Y)
+ public int GetSwizzleOffset(int X, int Y, int Z)
{
- return X * Bpp + Y * Pitch;
+ return Z * SliceSize + X * Bpp + Y * Pitch;
}
}
} \ No newline at end of file
diff --git a/Ryujinx.Graphics/Graphics3d/Texture/TextureFactory.cs b/Ryujinx.Graphics/Graphics3d/Texture/TextureFactory.cs
index 1f2d625e..a2ce86f5 100644
--- a/Ryujinx.Graphics/Graphics3d/Texture/TextureFactory.cs
+++ b/Ryujinx.Graphics/Graphics3d/Texture/TextureFactory.cs
@@ -12,6 +12,8 @@ namespace Ryujinx.Graphics.Texture
GalImageFormat Format = GetImageFormat(Tic);
+ GalTextureTarget TextureTarget = (GalTextureTarget)((Tic[4] >> 23) & 0xF);
+
GalTextureSource XSource = (GalTextureSource)((Tic[0] >> 19) & 7);
GalTextureSource YSource = (GalTextureSource)((Tic[0] >> 22) & 7);
GalTextureSource ZSource = (GalTextureSource)((Tic[0] >> 25) & 7);
@@ -19,6 +21,8 @@ namespace Ryujinx.Graphics.Texture
TextureSwizzle Swizzle = (TextureSwizzle)((Tic[2] >> 21) & 7);
+ int MaxMipmapLevel = (Tic[3] >> 28) & 0xF + 1;
+
GalMemoryLayout Layout;
if (Swizzle == TextureSwizzle.BlockLinear ||
@@ -31,22 +35,61 @@ namespace Ryujinx.Graphics.Texture
Layout = GalMemoryLayout.Pitch;
}
- int BlockHeightLog2 = (Tic[3] >> 3) & 7;
- int TileWidthLog2 = (Tic[3] >> 10) & 7;
+ int GobBlockHeightLog2 = (Tic[3] >> 3) & 7;
+ int GobBlockDepthLog2 = (Tic[3] >> 6) & 7;
+ int TileWidthLog2 = (Tic[3] >> 10) & 7;
+
+ int GobBlockHeight = 1 << GobBlockHeightLog2;
+ int GobBlockDepth = 1 << GobBlockDepthLog2;
+ int TileWidth = 1 << TileWidthLog2;
+
+ int Width = ((Tic[4] >> 0) & 0xffff) + 1;
+ int Height = ((Tic[5] >> 0) & 0xffff) + 1;
+ int Depth = ((Tic[5] >> 16) & 0x3fff) + 1;
+
+ int LayoutCount = 1;
- int BlockHeight = 1 << BlockHeightLog2;
- int TileWidth = 1 << TileWidthLog2;
+ // TODO: check this
+ if (ImageUtils.IsArray(TextureTarget))
+ {
+ LayoutCount = Depth;
+ Depth = 1;
+ }
+
+ if (TextureTarget == GalTextureTarget.OneD)
+ {
+ Height = 1;
+ }
- int Width = (Tic[4] & 0xffff) + 1;
- int Height = (Tic[5] & 0xffff) + 1;
+ if (TextureTarget == GalTextureTarget.TwoD || TextureTarget == GalTextureTarget.OneD)
+ {
+ Depth = 1;
+ }
+ else if (TextureTarget == GalTextureTarget.CubeMap)
+ {
+ // FIXME: This is a bit hacky but I guess it's fine for now
+ LayoutCount = 6;
+ Depth = 1;
+ }
+ else if (TextureTarget == GalTextureTarget.CubeArray)
+ {
+ // FIXME: This is a really really hacky but I guess it's fine for now
+ LayoutCount *= 6;
+ Depth = 1;
+ }
GalImage Image = new GalImage(
Width,
Height,
+ Depth,
+ LayoutCount,
TileWidth,
- BlockHeight,
+ GobBlockHeight,
+ GobBlockDepth,
Layout,
Format,
+ TextureTarget,
+ MaxMipmapLevel,
XSource,
YSource,
ZSource,
@@ -68,6 +111,10 @@ namespace Ryujinx.Graphics.Texture
GalTextureWrap AddressV = (GalTextureWrap)((Tsc[0] >> 3) & 7);
GalTextureWrap AddressP = (GalTextureWrap)((Tsc[0] >> 6) & 7);
+ bool DepthCompare = ((Tsc[0] >> 9) & 1) == 1;
+
+ DepthCompareFunc DepthCompareFunc = (DepthCompareFunc)((Tsc[0] >> 10) & 7);
+
GalTextureFilter MagFilter = (GalTextureFilter) ((Tsc[1] >> 0) & 3);
GalTextureFilter MinFilter = (GalTextureFilter) ((Tsc[1] >> 4) & 3);
GalTextureMipFilter MipFilter = (GalTextureMipFilter)((Tsc[1] >> 6) & 3);
@@ -85,7 +132,9 @@ namespace Ryujinx.Graphics.Texture
MinFilter,
MagFilter,
MipFilter,
- BorderColor);
+ BorderColor,
+ DepthCompare,
+ DepthCompareFunc);
}
private static GalImageFormat GetImageFormat(int[] Tic)
diff --git a/Ryujinx.Graphics/Graphics3d/Texture/TextureHelper.cs b/Ryujinx.Graphics/Graphics3d/Texture/TextureHelper.cs
index 6ac91d8b..33ccb0aa 100644
--- a/Ryujinx.Graphics/Graphics3d/Texture/TextureHelper.cs
+++ b/Ryujinx.Graphics/Graphics3d/Texture/TextureHelper.cs
@@ -1,4 +1,5 @@
using ChocolArm64.Memory;
+using Ryujinx.Common;
using Ryujinx.Graphics.Gal;
using Ryujinx.Graphics.Memory;
@@ -9,9 +10,13 @@ namespace Ryujinx.Graphics.Texture
public static ISwizzle GetSwizzle(GalImage Image)
{
int BlockWidth = ImageUtils.GetBlockWidth (Image.Format);
+ int BlockHeight = ImageUtils.GetBlockHeight (Image.Format);
+ int BlockDepth = ImageUtils.GetBlockDepth (Image.Format);
int BytesPerPixel = ImageUtils.GetBytesPerPixel(Image.Format);
- int Width = (Image.Width + (BlockWidth - 1)) / BlockWidth;
+ int Width = BitUtils.DivRoundUp(Image.Width, BlockWidth);
+ int Height = BitUtils.DivRoundUp(Image.Height, BlockHeight);
+ int Depth = BitUtils.DivRoundUp(Image.Depth, BlockDepth);
if (Image.Layout == GalMemoryLayout.BlockLinear)
{
@@ -19,11 +24,17 @@ namespace Ryujinx.Graphics.Texture
Width = (Width + AlignMask) & ~AlignMask;
- return new BlockLinearSwizzle(Width, BytesPerPixel, Image.GobBlockHeight);
+ return new BlockLinearSwizzle(
+ Width,
+ Height,
+ Depth,
+ Image.GobBlockHeight,
+ Image.GobBlockDepth,
+ BytesPerPixel);
}
else
{
- return new LinearSwizzle(Image.Pitch, BytesPerPixel);
+ return new LinearSwizzle(Image.Pitch, BytesPerPixel, Width, Height);
}
}
diff --git a/Ryujinx.Graphics/Texture/TextureInstructionSuffix.cs b/Ryujinx.Graphics/Texture/TextureInstructionSuffix.cs
new file mode 100644
index 00000000..bcb64af0
--- /dev/null
+++ b/Ryujinx.Graphics/Texture/TextureInstructionSuffix.cs
@@ -0,0 +1,19 @@
+using System;
+
+namespace Ryujinx.Graphics.Texture
+{
+ [Flags]
+ public enum TextureInstructionSuffix
+ {
+ None = 0x00, // No Modifier
+ LZ = 0x02, // Load LOD Zero
+ LB = 0x08, // Load Bias
+ LL = 0x10, // Load LOD
+ LBA = 0x20, // Load Bias with OperA? Auto?
+ LLA = 0x40, // Load LOD with OperA? Auto?
+ DC = 0x80, // Depth Compare
+ AOffI = 0x100, // Offset
+ MZ = 0x200, // Multisample Zero?
+ PTP = 0x400 // ???
+ }
+}
diff --git a/Ryujinx.Graphics/VDec/VideoDecoder.cs b/Ryujinx.Graphics/VDec/VideoDecoder.cs
index 847392b0..be53b1a0 100644
--- a/Ryujinx.Graphics/VDec/VideoDecoder.cs
+++ b/Ryujinx.Graphics/VDec/VideoDecoder.cs
@@ -216,10 +216,11 @@ namespace Ryujinx.Graphics.VDec
GalImage Image = new GalImage(
OutputConfig.SurfaceWidth,
- OutputConfig.SurfaceHeight, 1,
- OutputConfig.GobBlockHeight,
+ OutputConfig.SurfaceHeight, 1, 1, 1,
+ OutputConfig.GobBlockHeight, 1,
GalMemoryLayout.BlockLinear,
- GalImageFormat.RGBA8 | GalImageFormat.Unorm);
+ GalImageFormat.RGBA8 | GalImageFormat.Unorm,
+ GalTextureTarget.TwoD);
ImageUtils.WriteTexture(Vmm, Image, Vmm.GetPhysicalAddress(OutputConfig.SurfaceLumaAddress), Frame.Data);
}
diff --git a/Ryujinx.HLE/HOS/Services/Vi/NvFlinger.cs b/Ryujinx.HLE/HOS/Services/Vi/NvFlinger.cs
index db04f47c..dbf255be 100644
--- a/Ryujinx.HLE/HOS/Services/Vi/NvFlinger.cs
+++ b/Ryujinx.HLE/HOS/Services/Vi/NvFlinger.cs
@@ -1,6 +1,7 @@
using Ryujinx.Common.Logging;
using Ryujinx.Graphics.Gal;
using Ryujinx.Graphics.Memory;
+using Ryujinx.HLE.HOS.Kernel;
using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.HLE.HOS.Services.Nv.NvGpuAS;
using Ryujinx.HLE.HOS.Services.Nv.NvMap;
@@ -415,9 +416,10 @@ namespace Ryujinx.HLE.HOS.Services.Android
{
image = new GalImage(
fbWidth,
- fbHeight, 1, BlockHeight,
+ fbHeight, 1, 1, 1, BlockHeight, 1,
GalMemoryLayout.BlockLinear,
- imageFormat);
+ imageFormat,
+ GalTextureTarget.TwoD);
}
context.Device.Gpu.ResourceManager.ClearPbCache();
diff --git a/Ryujinx.ShaderTools/Program.cs b/Ryujinx.ShaderTools/Program.cs
index 30fa71ae..77aba0ab 100644
--- a/Ryujinx.ShaderTools/Program.cs
+++ b/Ryujinx.ShaderTools/Program.cs
@@ -13,7 +13,7 @@ namespace Ryujinx.ShaderTools
{
if (args.Length == 2)
{
- GlslDecompiler Decompiler = new GlslDecompiler(MaxUboSize);
+ GlslDecompiler Decompiler = new GlslDecompiler(MaxUboSize, true);
GalShaderType ShaderType = GalShaderType.Vertex;