This commit is contained in:
ReinUsesLisp 2018-08-30 18:02:39 +00:00 committed by GitHub
commit b1c410273b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 487 additions and 121 deletions

View file

@ -4,8 +4,10 @@ namespace Ryujinx.Graphics.Gal
{
public int Width;
public int Height;
public int Depth;
public GalImageFormat Format;
public GalImageTarget Target;
public GalTextureSource XSource;
public GalTextureSource YSource;
@ -15,7 +17,9 @@ namespace Ryujinx.Graphics.Gal
public GalImage(
int Width,
int Height,
int Depth,
GalImageFormat Format,
GalImageTarget Target,
GalTextureSource XSource = GalTextureSource.Red,
GalTextureSource YSource = GalTextureSource.Green,
GalTextureSource ZSource = GalTextureSource.Blue,
@ -23,7 +27,9 @@ namespace Ryujinx.Graphics.Gal
{
this.Width = Width;
this.Height = Height;
this.Depth = Depth;
this.Format = Format;
this.Target = Target;
this.XSource = XSource;
this.YSource = YSource;
this.ZSource = ZSource;

View file

@ -0,0 +1,15 @@
namespace Ryujinx.Graphics.Gal
{
public enum GalImageTarget
{
_1d = 0,
_2d = 1,
_3d = 2,
CubeMap = 3,
_1dArray = 4,
_2dArray = 5,
_1dBuffer = 6,
_2dNoMimap = 7, //GL_TEXTURE_RECTANGLE?
CubeArray = 8,
}
}

View file

@ -12,8 +12,6 @@ namespace Ryujinx.Graphics.Gal
void UnbindZeta();
void BindTexture(long Key, int Index);
void Set(long Key);
void Set(byte[] Data, int Width, int Height);

View file

@ -11,8 +11,6 @@ namespace Ryujinx.Graphics.Gal
bool TryGetCachedTexture(long Key, long DataSize, out GalImage Image);
void Bind(long Key, int Index);
void SetSampler(GalTextureSampler Sampler);
void Bind(long Key, int Index, GalTextureSampler Sampler);
}
}

View file

@ -34,8 +34,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
public ImageHandler(int Handle, GalImage Image)
{
this.Handle = Handle;
this.Image = Image;
this.Image = Image;
}
public void EnsureSetup(GalImage Image)
@ -48,7 +47,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL
(PixelInternalFormat InternalFormat, PixelFormat PixelFormat, PixelType PixelType) =
OGLEnumConverter.GetImageFormat(Image.Format);
GL.BindTexture(TextureTarget.Texture2D, Handle);
TextureTarget Target = OGLEnumConverter.GetImageTarget(Image.Target);
GL.BindTexture(Target, Handle);
if (Initialized)
{
@ -72,7 +73,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
GL.BufferData(BufferTarget.PixelPackBuffer, CurrentSize, IntPtr.Zero, BufferUsageHint.StreamCopy);
}
GL.GetTexImage(TextureTarget.Texture2D, 0, this.PixelFormat, this.PixelType, IntPtr.Zero);
GL.GetTexImage(Target, 0, this.PixelFormat, this.PixelType, IntPtr.Zero);
GL.DeleteTexture(Handle);
@ -84,22 +85,23 @@ namespace Ryujinx.Graphics.Gal.OpenGL
const int MinFilter = (int)TextureMinFilter.Linear;
const int MagFilter = (int)TextureMagFilter.Linear;
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, MinFilter);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, MagFilter);
GL.TexParameter(Target, TextureParameterName.TextureMinFilter, MinFilter);
GL.TexParameter(Target, TextureParameterName.TextureMagFilter, MagFilter);
const int Level = 0;
const int Border = 0;
GL.TexImage2D(
TextureTarget.Texture2D,
OGLHelper.TexImage(
Target,
Level,
InternalFormat,
Image.Width,
Image.Height,
Image.Depth,
Border,
PixelFormat,
PixelType,
IntPtr.Zero);
null);
if (Initialized)
{

View file

@ -317,5 +317,19 @@ namespace Ryujinx.Graphics.Gal.OpenGL
throw new ArgumentException(nameof(BlendFactor));
}
public static TextureTarget GetImageTarget(GalImageTarget Target)
{
switch (Target)
{
case GalImageTarget._1d: return TextureTarget.Texture1D;
case GalImageTarget._2d: return TextureTarget.Texture2D;
case GalImageTarget._2dArray: return TextureTarget.Texture2DArray;
case GalImageTarget._3d: return TextureTarget.Texture3D;
case GalImageTarget.CubeMap: return TextureTarget.TextureCubeMap;
}
throw new NotImplementedException(Target.ToString());
}
}
}

View file

@ -148,16 +148,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL
}
}
public void BindTexture(long Key, int Index)
{
if (Texture.TryGetImage(Key, out ImageHandler Tex))
{
GL.ActiveTexture(TextureUnit.Texture0 + Index);
GL.BindTexture(TextureTarget.Texture2D, Tex.Handle);
}
}
public void Set(long Key)
{
if (Texture.TryGetImage(Key, out ImageHandler Tex))
@ -173,7 +163,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
RawTex = new ImageHandler();
}
RawTex.EnsureSetup(new GalImage(Width, Height, RawFormat));
RawTex.EnsureSetup(new GalImage(Width, Height, 1, RawFormat, GalImageTarget._2d));
GL.BindTexture(TextureTarget.Texture2D, RawTex.Handle);

View file

@ -0,0 +1,193 @@
using OpenTK.Graphics.OpenGL;
using System;
namespace Ryujinx.Graphics.Gal.OpenGL
{
public static class OGLHelper
{
public static unsafe void TexImage(
TextureTarget Target,
int Level,
PixelInternalFormat InternalFormat,
int Width,
int Height,
int Depth,
int Border,
PixelFormat PixelFormat,
PixelType PixelType,
byte[] Data)
{
switch (Target)
{
case TextureTarget.Texture1D:
GL.TexImage1D(
Target,
Level,
InternalFormat,
Width,
Border,
PixelFormat,
PixelType,
Data);
break;
case TextureTarget.Texture2D:
GL.TexImage2D(
Target,
Level,
InternalFormat,
Width,
Height,
Border,
PixelFormat,
PixelType,
Data);
break;
case TextureTarget.Texture2DArray:
case TextureTarget.Texture3D:
//FIXME: Unstub depth when swizzle is fixed
Depth = 1;
GL.TexImage3D(
Target,
Level,
InternalFormat,
Width,
Height,
Depth,
Border,
PixelFormat,
PixelType,
Data);
break;
case TextureTarget.TextureCubeMap:
{
long FaceSize = Data.LongLength / 6;
for (int Face = 0; Face < 6; Face++)
{
fixed (byte* DataPtr = Data)
{
IntPtr Addr;
if (Data != null)
{
Addr = new IntPtr(DataPtr + FaceSize * Face);
}
else
{
Addr = new IntPtr(0);
}
GL.TexImage2D(
TextureTarget.TextureCubeMapPositiveX + Face,
Level,
InternalFormat,
Width,
Height,
Border,
PixelFormat,
PixelType,
Addr);
}
}
break;
}
default:
throw new NotImplementedException(Target.ToString());
}
}
public static unsafe void CompressedTexImage(
TextureTarget Target,
int Level,
InternalFormat InternalFormat,
int Width,
int Height,
int Depth,
int Border,
byte[] Data)
{
switch (Target)
{
case TextureTarget.Texture1D:
GL.CompressedTexImage1D(
Target,
Level,
InternalFormat,
Width,
Border,
Data.Length,
Data);
break;
case TextureTarget.Texture2D:
GL.CompressedTexImage2D(
Target,
Level,
InternalFormat,
Width,
Height,
Border,
Data.Length,
Data);
break;
case TextureTarget.Texture2DArray:
case TextureTarget.Texture3D:
//FIXME: Unstub depth when swizzle is fixed
Depth = 1;
GL.CompressedTexImage3D(
Target,
Level,
InternalFormat,
Width,
Height,
Depth,
Border,
Data.Length,
Data);
break;
case TextureTarget.TextureCubeMap:
{
//FIXME: This implies that all 6 faces are equal
int FaceSize = Data.Length / 6;
for (int Face = 0; Face < 6; Face++)
{
fixed (byte* DataPtr = Data)
{
IntPtr Addr;
if (Data != null)
{
Addr = new IntPtr(DataPtr + FaceSize * Face);
}
else
{
Addr = new IntPtr(0);
}
GL.CompressedTexImage2D(
TextureTarget.TextureCubeMapPositiveX + Face,
Level,
InternalFormat,
Width,
Height,
Border,
FaceSize,
Addr);
}
}
break;
}
default:
throw new NotImplementedException(Target.ToString());
}
}
}
}

View file

@ -34,7 +34,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL
TextureCache.AddOrUpdate(Key, new ImageHandler(Handle, Image), (uint)Data.Length);
GL.BindTexture(TextureTarget.Texture2D, Handle);
TextureTarget Target = OGLEnumConverter.GetImageTarget(Image.Target);
GL.BindTexture(Target, Handle);
const int Level = 0; //TODO: Support mipmap textures.
const int Border = 0;
@ -43,21 +45,21 @@ namespace Ryujinx.Graphics.Gal.OpenGL
{
InternalFormat InternalFmt = OGLEnumConverter.GetCompressedImageFormat(Image.Format);
GL.CompressedTexImage2D(
TextureTarget.Texture2D,
OGLHelper.CompressedTexImage(
Target,
Level,
InternalFmt,
Image.Width,
Image.Height,
Image.Depth,
Border,
Data.Length,
Data);
}
else
{
if (Image.Format >= GalImageFormat.ASTC_BEGIN && Image.Format <= GalImageFormat.ASTC_END)
{
int TextureBlockWidth = GetAstcBlockWidth(Image.Format);
int TextureBlockWidth = GetAstcBlockWidth (Image.Format);
int TextureBlockHeight = GetAstcBlockHeight(Image.Format);
Data = ASTCDecoder.DecodeToRGBA8888(
@ -72,12 +74,13 @@ namespace Ryujinx.Graphics.Gal.OpenGL
(PixelInternalFormat InternalFormat, PixelFormat Format, PixelType Type) = OGLEnumConverter.GetImageFormat(Image.Format);
GL.TexImage2D(
TextureTarget.Texture2D,
OGLHelper.TexImage(
Target,
Level,
InternalFormat,
Image.Width,
Image.Height,
Image.Depth,
Border,
Format,
Type,
@ -89,10 +92,10 @@ namespace Ryujinx.Graphics.Gal.OpenGL
int SwizzleB = (int)OGLEnumConverter.GetTextureSwizzle(Image.ZSource);
int SwizzleA = (int)OGLEnumConverter.GetTextureSwizzle(Image.WSource);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleR, SwizzleR);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleG, SwizzleG);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleB, SwizzleB);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleA, SwizzleA);
GL.TexParameter(Target, TextureParameterName.TextureSwizzleR, SwizzleR);
GL.TexParameter(Target, TextureParameterName.TextureSwizzleG, SwizzleG);
GL.TexParameter(Target, TextureParameterName.TextureSwizzleB, SwizzleB);
GL.TexParameter(Target, TextureParameterName.TextureSwizzleA, SwizzleA);
}
public void CreateFb(long Key, long Size, GalImage Image)
@ -182,29 +185,30 @@ namespace Ryujinx.Graphics.Gal.OpenGL
return false;
}
public void Bind(long Key, int Index)
public void Bind(long Key, int Index, GalTextureSampler Sampler)
{
if (TextureCache.TryGetValue(Key, out ImageHandler CachedImage))
if (!TextureCache.TryGetValue(Key, out ImageHandler CachedImage))
{
GL.ActiveTexture(TextureUnit.Texture0 + Index);
GL.BindTexture(TextureTarget.Texture2D, CachedImage.Handle);
return;
}
}
public void SetSampler(GalTextureSampler Sampler)
{
TextureTarget Target = OGLEnumConverter.GetImageTarget(CachedImage.Image.Target);
GL.ActiveTexture(TextureUnit.Texture0 + Index);
GL.BindTexture(Target, CachedImage.Handle);
int WrapS = (int)OGLEnumConverter.GetTextureWrapMode(Sampler.AddressU);
int WrapT = (int)OGLEnumConverter.GetTextureWrapMode(Sampler.AddressV);
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);
GL.TexParameter(Target, TextureParameterName.TextureWrapS, WrapS);
GL.TexParameter(Target, TextureParameterName.TextureWrapT, WrapT);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, MinFilter);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, MagFilter);
GL.TexParameter(Target, TextureParameterName.TextureMinFilter, MinFilter);
GL.TexParameter(Target, TextureParameterName.TextureMagFilter, MagFilter);
float[] Color = new float[]
{
@ -214,7 +218,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
Sampler.BorderColor.Alpha
};
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureBorderColor, Color);
GL.TexParameter(Target, TextureParameterName.TextureBorderColor, Color);
}
private static bool IsCompressedTextureFormat(GalImageFormat Format)

View file

@ -63,6 +63,8 @@ namespace Ryujinx.Graphics.Gal.Shader
private Dictionary<int, ShaderDeclInfo> m_Gprs;
private Dictionary<int, ShaderDeclInfo> m_Preds;
private Dictionary<int, ShaderTextureType> m_TextureTypes;
public IReadOnlyDictionary<ShaderIrOp, ShaderDeclInfo> CbTextures => m_CbTextures;
public IReadOnlyDictionary<int, ShaderDeclInfo> Textures => m_Textures;
@ -75,6 +77,8 @@ namespace Ryujinx.Graphics.Gal.Shader
public IReadOnlyDictionary<int, ShaderDeclInfo> Gprs => m_Gprs;
public IReadOnlyDictionary<int, ShaderDeclInfo> Preds => m_Preds;
public IReadOnlyDictionary<int, ShaderTextureType> TextureTypes => m_TextureTypes;
public GalShaderType ShaderType { get; private set; }
private GlslDecl(GalShaderType ShaderType)
@ -92,6 +96,8 @@ namespace Ryujinx.Graphics.Gal.Shader
m_Gprs = new Dictionary<int, ShaderDeclInfo>();
m_Preds = new Dictionary<int, ShaderDeclInfo>();
m_TextureTypes = new Dictionary<int, ShaderTextureType>();
}
public GlslDecl(ShaderIrBlock[] Blocks, GalShaderType ShaderType, ShaderHeader Header)
@ -221,16 +227,26 @@ namespace Ryujinx.Graphics.Gal.Shader
Op.Inst == ShaderIrInst.Texs ||
Op.Inst == ShaderIrInst.Txlf)
{
int Handle = ((ShaderIrOperImm)Op.OperandC).Value;
ShaderIrMetaTex Meta = (ShaderIrMetaTex)Op.MetaData;
Traverse(Nodes, Op, Meta.Index);
int Handle = ((ShaderIrOperImm)Meta.Index).Value;
int Index = Handle - TexStartIndex;
string Name = StagePrefix + TextureName + Index;
m_Textures.TryAdd(Handle, new ShaderDeclInfo(Name, Handle));
m_TextureTypes.TryAdd(Handle, Meta.Type);
}
else if (Op.Inst == ShaderIrInst.Texb)
{
ShaderIrMetaTex Meta = (ShaderIrMetaTex)Op.MetaData;
Traverse(Nodes, Op, Meta.Index);
ShaderIrNode HandleSrc = null;
int Index = Array.IndexOf(Nodes, Parent) - 1;
@ -241,7 +257,7 @@ namespace Ryujinx.Graphics.Gal.Shader
if (Curr is ShaderIrAsg Asg && Asg.Dst is ShaderIrOperGpr Gpr)
{
if (Gpr.Index == ((ShaderIrOperGpr)Op.OperandC).Index)
if (Gpr.Index == ((ShaderIrOperGpr)Meta.Index).Index)
{
HandleSrc = Asg.Src;
@ -255,6 +271,8 @@ namespace Ryujinx.Graphics.Gal.Shader
string Name = StagePrefix + TextureName + "_cb" + Cbuf.Index + "_" + Cbuf.Pos;
m_CbTextures.Add(Op, new ShaderDeclInfo(Name, Cbuf.Pos, true, Cbuf.Index));
//TODO: Add m_CbTextures to texture types
}
else
{

View file

@ -145,8 +145,6 @@ namespace Ryujinx.Graphics.Gal.Shader
{
SB = new StringBuilder();
SB.AppendLine("#version 410 core");
PrintDeclHeader();
PrintDeclTextures();
PrintDeclUniforms();
@ -185,6 +183,8 @@ namespace Ryujinx.Graphics.Gal.Shader
private void PrintDeclHeader()
{
SB.AppendLine("#version 410 core");
if (Decl.ShaderType == GalShaderType.Geometry)
{
int MaxVertices = Header.MaxOutputVertexCount;
@ -209,9 +209,9 @@ namespace Ryujinx.Graphics.Gal.Shader
SB.AppendLine("layout(triangles) in;" + Environment.NewLine);
SB.AppendLine($"layout({OutputTopology}, max_vertices = {MaxVertices}) out;");
SB.AppendLine();
}
SB.AppendLine();
}
private void PrintDeclTextures()
@ -221,7 +221,16 @@ namespace Ryujinx.Graphics.Gal.Shader
SB.AppendLine("uniform sampler2D " + DeclInfo.Name + ";");
}
PrintDecls(Decl.Textures, "uniform sampler2D");
foreach (ShaderDeclInfo DeclInfo in Decl.Textures.Values.OrderBy(DeclKeySelector))
{
ShaderTextureType Type = Decl.TextureTypes[DeclInfo.Index];
string TypeName = GetSamplerName(Type);
SB.AppendLine("uniform " + TypeName + " " + DeclInfo.Name + ";");
}
SB.AppendLine();
}
private IEnumerable<ShaderDeclInfo> IterateCbTextures()
@ -250,11 +259,9 @@ namespace Ryujinx.Graphics.Gal.Shader
SB.AppendLine(IdentationStr + "int " + GlslDecl.InstanceUniformName + ";");
SB.AppendLine("};");
SB.AppendLine("};" + Environment.NewLine);
}
SB.AppendLine();
foreach (ShaderDeclInfo DeclInfo in Decl.Uniforms.Values.OrderBy(DeclKeySelector))
{
SB.AppendLine($"layout (std140) uniform {DeclInfo.Name} {{");
@ -1188,9 +1195,9 @@ namespace Ryujinx.Graphics.Gal.Shader
private string GetTexSamplerName(ShaderIrOp Op)
{
ShaderIrOperImm Node = (ShaderIrOperImm)Op.OperandC;
ShaderIrNode Node = ((ShaderIrMetaTex)Op.MetaData).Index;
int Handle = ((ShaderIrOperImm)Op.OperandC).Value;
int Handle = ((ShaderIrOperImm)Node).Value;
if (!Decl.Textures.TryGetValue(Handle, out ShaderDeclInfo DeclInfo))
{
@ -1202,14 +1209,40 @@ namespace Ryujinx.Graphics.Gal.Shader
private string GetTexSamplerCoords(ShaderIrOp Op)
{
return "vec2(" + GetOperExpr(Op, Op.OperandA) + ", " +
GetOperExpr(Op, Op.OperandB) + ")";
if (Op.OperandC != null)
{
return "vec3(" + GetOperExpr(Op, Op.OperandA) + ", " +
GetOperExpr(Op, Op.OperandB) + ", " +
GetOperExpr(Op, Op.OperandC) + ")";
}
else if (Op.OperandB != null)
{
return "vec2(" + GetOperExpr(Op, Op.OperandA) + ", " +
GetOperExpr(Op, Op.OperandB) + ")";
}
else
{
return GetOperExpr(Op, Op.OperandA);
}
}
private string GetITexSamplerCoords(ShaderIrOp Op)
{
return "ivec2(" + GetOperExpr(Op, Op.OperandA) + ", " +
GetOperExpr(Op, Op.OperandB) + ")";
if (Op.OperandC != null)
{
return "ivec3(" + GetOperExpr(Op, Op.OperandA) + ", " +
GetOperExpr(Op, Op.OperandB) + ", " +
GetOperExpr(Op, Op.OperandC) + ")";
}
else if (Op.OperandB != null)
{
return "ivec2(" + GetOperExpr(Op, Op.OperandA) + ", " +
GetOperExpr(Op, Op.OperandB) + ")";
}
else
{
return GetOperExpr(Op, Op.OperandA);
}
}
private string GetOperExpr(ShaderIrOp Op, ShaderIrNode Oper)
@ -1351,5 +1384,19 @@ namespace Ryujinx.Graphics.Gal.Shader
throw new ArgumentException(nameof(Node));
}
private static string GetSamplerName(ShaderTextureType Type)
{
switch (Type)
{
case ShaderTextureType._1d: return "sampler1D";
case ShaderTextureType._2d: return "sampler2D";
case ShaderTextureType._2dArray: return "sampler2DArray";
case ShaderTextureType._3d: return "sampler3D";
case ShaderTextureType.Cube: return "samplerCube";
}
throw new NotImplementedException(Type.ToString());
}
}
}

View file

@ -31,13 +31,38 @@ namespace Ryujinx.Graphics.Gal.Shader
{ RGB_, RG_A, R_BA, _GBA, RGBA, ____, ____, ____ }
};
private static ShaderTextureType[,] TexTypes = new ShaderTextureType[,]
{
{ ShaderTextureType._1d, ShaderTextureType._1dArray },
{ ShaderTextureType._2d, ShaderTextureType._2dArray },
{ ShaderTextureType._3d, ShaderTextureType.Invalid },
{ ShaderTextureType.Cube, ShaderTextureType.Invalid }
};
private static int[] TexTypeCoords = new int[] { 1, 2, 3, 3 };
private static ShaderTextureType[] TexsTypes = new ShaderTextureType[]
{
ShaderTextureType._1d,
ShaderTextureType._2d,
ShaderTextureType._2d,
ShaderTextureType._2d,
ShaderTextureType._2d,
ShaderTextureType._2d,
ShaderTextureType._2d,
ShaderTextureType._2dArray,
ShaderTextureType._2dArray,
ShaderTextureType._2dArray,
ShaderTextureType._3d,
ShaderTextureType._3d,
ShaderTextureType.Cube,
ShaderTextureType.Cube,
};
public static void Ld_A(ShaderIrBlock Block, long OpCode)
{
ShaderIrNode[] Opers = GetOperAbuf20(OpCode);
//Used by GS
ShaderIrOperGpr Vertex = GetOperGpr39(OpCode);
int Index = 0;
foreach (ShaderIrNode OperA in Opers)
@ -118,15 +143,15 @@ namespace Ryujinx.Graphics.Gal.Shader
ShaderIrNode OperD = GetOperGpr0(OpCode);
ShaderIrNode OperA = GetOperGpr8(OpCode);
ShaderIrNode TextureIndex = GetOperImm13_36(OpCode);
ShaderTexqInfo Info = (ShaderTexqInfo)((OpCode >> 22) & 0x1f);
ShaderIrMetaTexq Meta0 = new ShaderIrMetaTexq(Info, 0);
ShaderIrMetaTexq Meta1 = new ShaderIrMetaTexq(Info, 1);
ShaderIrMetaTexq Meta0 = new ShaderIrMetaTexq(Info, ShaderTextureType._2d, TextureIndex, 0);
ShaderIrMetaTexq Meta1 = new ShaderIrMetaTexq(Info, ShaderTextureType._2d, TextureIndex, 1);
ShaderIrNode OperC = GetOperImm13_36(OpCode);
ShaderIrOp Op0 = new ShaderIrOp(ShaderIrInst.Texq, OperA, null, OperC, Meta0);
ShaderIrOp Op1 = new ShaderIrOp(ShaderIrInst.Texq, OperA, null, OperC, Meta1);
ShaderIrOp Op0 = new ShaderIrOp(ShaderIrInst.Texq, OperA, null, null, Meta0);
ShaderIrOp Op1 = new ShaderIrOp(ShaderIrInst.Texq, OperA, null, null, Meta1);
Block.AddNode(GetPredNode(new ShaderIrAsg(OperD, Op0), OpCode));
Block.AddNode(GetPredNode(new ShaderIrAsg(OperA, Op1), OpCode)); //Is this right?
@ -144,14 +169,22 @@ namespace Ryujinx.Graphics.Gal.Shader
private static void EmitTex(ShaderIrBlock Block, long OpCode, bool GprHandle)
{
//TODO: Support other formats.
ShaderIrOperGpr[] Coords = new ShaderIrOperGpr[2];
bool IsArray = ((OpCode >> 28) & 1) != 0;
for (int Index = 0; Index < Coords.Length; Index++)
int TypeId = (int)((OpCode >> 29) & 3);
ShaderIrOperGpr[] Coords = new ShaderIrOperGpr[3];
ShaderTextureType Type = TexTypes[TypeId, IsArray ? 1 : 0];
if (Type == ShaderTextureType.Invalid)
{
Coords[Index] = GetOperGpr8(OpCode);
throw new InvalidOperationException();
}
Coords[Index].Index += Index;
for (int Index = 0; Index < TexTypeCoords[TypeId] + (IsArray ? 1 : 0); Index++)
{
Coords[Index] = GetOperGpr8(OpCode) + Index;
if (Coords[Index].Index > ShaderIrOperGpr.ZRIndex)
{
@ -161,7 +194,7 @@ namespace Ryujinx.Graphics.Gal.Shader
int ChMask = (int)(OpCode >> 31) & 0xf;
ShaderIrNode OperC = GprHandle
ShaderIrNode TextureIndex = GprHandle
? (ShaderIrNode)GetOperGpr20 (OpCode)
: (ShaderIrNode)GetOperImm13_36(OpCode);
@ -171,9 +204,9 @@ namespace Ryujinx.Graphics.Gal.Shader
{
ShaderIrOperGpr Dst = new ShaderIrOperGpr(TempRegStart + Ch);
ShaderIrMetaTex Meta = new ShaderIrMetaTex(Ch);
ShaderIrMetaTex Meta = new ShaderIrMetaTex(Type, TextureIndex, Ch);
ShaderIrOp Op = new ShaderIrOp(Inst, Coords[0], Coords[1], OperC, Meta);
ShaderIrOp Op = new ShaderIrOp(Inst, Coords[0], Coords[1], Coords[2], Meta);
Block.AddNode(GetPredNode(new ShaderIrAsg(Dst, Op), OpCode));
}
@ -214,10 +247,7 @@ namespace Ryujinx.Graphics.Gal.Shader
private static void EmitTexs(ShaderIrBlock Block, long OpCode, ShaderIrInst Inst)
{
//TODO: Support other formats.
ShaderIrNode OperA = GetOperGpr8 (OpCode);
ShaderIrNode OperB = GetOperGpr20 (OpCode);
ShaderIrNode OperC = GetOperImm13_36(OpCode);
ShaderIrNode TextureIndex = GetOperImm13_36(OpCode);
int LutIndex;
@ -233,11 +263,50 @@ namespace Ryujinx.Graphics.Gal.Shader
int ChMask = MaskLut[LutIndex, (OpCode >> 50) & 7];
long TypeIndex = (OpCode >> 53) & 0xf;
ShaderTextureType Type = TexsTypes[TypeIndex];
ShaderIrNode OperA = null;
ShaderIrNode OperB = null;
ShaderIrNode OperC = null;
switch (Type)
{
case ShaderTextureType._2d:
OperA = GetOperGpr8 (OpCode);
OperB = GetOperGpr20(OpCode);
break;
case ShaderTextureType._2dArray:
OperA = GetOperGpr8 (OpCode) + 1;
OperB = GetOperGpr20(OpCode);
OperC = GetOperGpr8 (OpCode);
break;
//This layout is copy-pasted, complitely untested
case ShaderTextureType._3d:
OperA = GetOperGpr8(OpCode) + 1;
OperB = GetOperGpr20(OpCode);
OperC = GetOperGpr8(OpCode);
break;
//Unsure about this layout
case ShaderTextureType.Cube:
OperA = GetOperGpr8 (OpCode);
OperB = GetOperGpr8 (OpCode) + 1;
OperC = GetOperGpr20(OpCode);
break;
default:
throw new NotImplementedException(Type.ToString());
}
for (int Ch = 0; Ch < 4; Ch++)
{
ShaderIrOperGpr Dst = new ShaderIrOperGpr(TempRegStart + Ch);
ShaderIrMetaTex Meta = new ShaderIrMetaTex(Ch);
ShaderIrMetaTex Meta = new ShaderIrMetaTex(Type, TextureIndex, Ch);
ShaderIrOp Op = new ShaderIrOp(Inst, OperA, OperB, OperC, Meta);

View file

@ -2,11 +2,17 @@ namespace Ryujinx.Graphics.Gal.Shader
{
class ShaderIrMetaTex : ShaderIrMeta
{
public ShaderTextureType Type { get; private set; }
public ShaderIrNode Index { get; private set; }
public int Elem { get; private set; }
public ShaderIrMetaTex(int Elem)
public ShaderIrMetaTex(ShaderTextureType Type, ShaderIrNode Index, int Elem)
{
this.Elem = Elem;
this.Type = Type;
this.Index = Index;
this.Elem = Elem;
}
}
}

View file

@ -1,15 +1,13 @@
namespace Ryujinx.Graphics.Gal.Shader
{
class ShaderIrMetaTexq : ShaderIrMeta
class ShaderIrMetaTexq : ShaderIrMetaTex
{
public ShaderTexqInfo Info { get; private set; }
public int Elem { get; private set; }
public ShaderIrMetaTexq(ShaderTexqInfo Info, int Elem)
public ShaderIrMetaTexq(ShaderTexqInfo Info, ShaderTextureType Type, ShaderIrNode Index, int Elem)
: base(Type, Index, Elem)
{
this.Info = Info;
this.Elem = Elem;
}
}
}

View file

@ -15,6 +15,11 @@ namespace Ryujinx.Graphics.Gal.Shader
this.Index = Index;
}
public static ShaderIrOperGpr operator+(ShaderIrOperGpr Gpr, int PlusIndex)
{
return new ShaderIrOperGpr(Gpr.Index + PlusIndex);
}
public static ShaderIrOperGpr MakeTemporary(int Index = 0)
{
return new ShaderIrOperGpr(0x100 + Index);

View file

@ -0,0 +1,13 @@
namespace Ryujinx.Graphics.Gal.Shader
{
enum ShaderTextureType
{
Invalid,
_1d,
_1dArray,
_2d,
_2dArray,
_3d,
Cube
}
}

View file

@ -202,7 +202,7 @@ namespace Ryujinx.HLE.Gpu.Engines
GalImageFormat ImageFormat = ImageFormatConverter.ConvertFrameBuffer((GalFrameBufferFormat)Format);
GalImage Image = new GalImage(Width, Height, ImageFormat);
GalImage Image = new GalImage(Width, Height, 1, ImageFormat, GalImageTarget._2d);
long Size = TextureHelper.GetTextureSize(Image);
@ -234,7 +234,7 @@ namespace Ryujinx.HLE.Gpu.Engines
GalImageFormat ImageFormat = ImageFormatConverter.ConvertZeta((GalZetaFormat)Format);
GalImage Image = new GalImage(Width, Height, ImageFormat);
GalImage Image = new GalImage(Width, Height, 1, ImageFormat, GalImageTarget._2d);
long Size = TextureHelper.GetTextureSize(Image);
@ -509,47 +509,32 @@ namespace Ryujinx.HLE.Gpu.Engines
if (Key == -1)
{
//FIXME: Should'nt ignore invalid addresses.
//FIXME: Shouldn't ignore invalid addresses.
return;
}
if (IsFrameBufferPosition(Key))
{
//This texture is a frame buffer texture,
//we shouldn't read anything from memory and bind
//the frame buffer texture instead, since we're not
//really writing anything to memory.
Gpu.Renderer.FrameBuffer.BindTexture(Key, TexIndex);
}
else
//If a texture is a rendertarget texture,
//we shouldn't read anything from memory and just bind it
if (!IsFrameBufferPosition(Key))
{
GalImage NewImage = TextureFactory.MakeTexture(Vmm, TicPosition);
long Size = (uint)TextureHelper.GetTextureSize(NewImage);
bool HasCachedTexture = false;
bool Exists = Gpu.Renderer.Texture.TryGetCachedTexture(Key, Size, out GalImage Image);
if (Gpu.Renderer.Texture.TryGetCachedTexture(Key, Size, out GalImage Image))
{
if (NewImage.Equals(Image) && !QueryKeyUpload(Vmm, Key, Size, NvGpuBufferType.Texture))
{
Gpu.Renderer.Texture.Bind(Key, TexIndex);
HasCachedTexture = true;
}
}
if (!HasCachedTexture)
if (!Exists ||
!NewImage.Equals(Image) ||
QueryKeyUpload(Vmm, Key, Size, NvGpuBufferType.Texture))
{
byte[] Data = TextureFactory.GetTextureData(Vmm, TicPosition);
Gpu.Renderer.Texture.Create(Key, Data, NewImage);
}
Gpu.Renderer.Texture.Bind(Key, TexIndex);
}
Gpu.Renderer.Texture.SetSampler(Sampler);
Gpu.Renderer.Texture.Bind(Key, TexIndex, Sampler);
}
private void UploadConstBuffers(NvGpuVmm Vmm, GalPipelineState State, long[] Keys)

View file

@ -24,11 +24,16 @@ namespace Ryujinx.HLE.Gpu.Texture
int Width = (Tic[4] & 0xffff) + 1;
int Height = (Tic[5] & 0xffff) + 1;
int Depth = ((Tic[5] >> 16) & 0x7fff) + 1;
GalImageTarget Target = (GalImageTarget)((Tic[4] >> 23) & 0xf);
return new GalImage(
Width,
Height,
Depth,
Format,
Target,
XSource,
YSource,
ZSource,