Started to implement texture decoding on the GAL
This commit is contained in:
parent
1132b6edae
commit
8f0f1c489c
16 changed files with 310 additions and 148 deletions
20
Ryujinx.Graphics/Gal/GalTexture.cs
Normal file
20
Ryujinx.Graphics/Gal/GalTexture.cs
Normal file
|
@ -0,0 +1,20 @@
|
|||
namespace Ryujinx.Graphics.Gal
|
||||
{
|
||||
public struct GalTexture
|
||||
{
|
||||
public byte[] Data;
|
||||
|
||||
public int Width;
|
||||
public int Height;
|
||||
|
||||
public GalTextureFormat Format;
|
||||
|
||||
public GalTexture(byte[] Data, int Width, int Height, GalTextureFormat Format)
|
||||
{
|
||||
this.Data = Data;
|
||||
this.Width = Width;
|
||||
this.Height = Height;
|
||||
this.Format = Format;
|
||||
}
|
||||
}
|
||||
}
|
10
Ryujinx.Graphics/Gal/GalTextureFormat.cs
Normal file
10
Ryujinx.Graphics/Gal/GalTextureFormat.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
namespace Ryujinx.Graphics.Gal
|
||||
{
|
||||
public enum GalTextureFormat
|
||||
{
|
||||
A8B8G8R8 = 0x8,
|
||||
BC1 = 0x24,
|
||||
BC2 = 0x25,
|
||||
BC3 = 0x26
|
||||
}
|
||||
}
|
|
@ -25,16 +25,19 @@ namespace Ryujinx.Graphics.Gal
|
|||
void ClearBuffers(int RtIndex, GalClearBufferFlags Flags);
|
||||
|
||||
void SetVertexArray(int VbIndex, int Stride, byte[] Buffer, GalVertexAttrib[] Attribs);
|
||||
|
||||
void RenderVertexArray(int VbIndex);
|
||||
|
||||
//Shader
|
||||
void CreateShader(long Tag, GalShaderType Type, byte[] Data);
|
||||
void SetShaderCb(long Tag, int Cbuf, byte[] Data);
|
||||
|
||||
void SetShaderConstBuffer(long Tag, int Cbuf, byte[] Data);
|
||||
|
||||
void BindShader(long Tag);
|
||||
|
||||
void BindProgram();
|
||||
|
||||
void SendR8G8B8A8Texture(int Index, byte[] Buffer, int Width, int Height);
|
||||
|
||||
void BindTexture(int Index);
|
||||
//Texture
|
||||
void UpdateTextures(Func<int, GalShaderType, GalTexture> RequestTextureCallback);
|
||||
}
|
||||
}
|
|
@ -87,6 +87,25 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
}
|
||||
}
|
||||
|
||||
public IEnumerable<ShaderDeclInfo> GetTextureUsage(GalShaderType ShaderType)
|
||||
{
|
||||
switch (ShaderType)
|
||||
{
|
||||
case GalShaderType.Vertex: return GetTextureUsage(Current.Vertex);
|
||||
case GalShaderType.TessControl: return GetTextureUsage(Current.TessControl);
|
||||
case GalShaderType.TessEvaluation: return GetTextureUsage(Current.TessEvaluation);
|
||||
case GalShaderType.Geometry: return GetTextureUsage(Current.Geometry);
|
||||
case GalShaderType.Fragment: return GetTextureUsage(Current.Fragment);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private IEnumerable<ShaderDeclInfo> GetTextureUsage(ShaderStage Stage)
|
||||
{
|
||||
return Stage?.TextureUsage ?? Enumerable.Empty<ShaderDeclInfo>();
|
||||
}
|
||||
|
||||
public void SetConstBuffer(long Tag, int Cbuf, byte[] Data)
|
||||
{
|
||||
if (Stages.TryGetValue(Tag, out ShaderStage Stage))
|
||||
|
|
87
Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs
Normal file
87
Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs
Normal file
|
@ -0,0 +1,87 @@
|
|||
using OpenTK.Graphics.OpenGL;
|
||||
using Ryujinx.Graphics.Gal.Texture;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Gal.OpenGL
|
||||
{
|
||||
class OGLTexture
|
||||
{
|
||||
private OGLShader Shader;
|
||||
|
||||
private int[] Textures;
|
||||
|
||||
private int CurrentTextureIndex;
|
||||
|
||||
public OGLTexture(OGLShader Shader)
|
||||
{
|
||||
this.Shader = Shader;
|
||||
|
||||
Textures = new int[80];
|
||||
}
|
||||
|
||||
public void UpdateTextures(Func<int, GalShaderType, GalTexture> RequestTextureCallback)
|
||||
{
|
||||
CurrentTextureIndex = 0;
|
||||
|
||||
UpdateTextures(RequestTextureCallback, GalShaderType.Vertex);
|
||||
UpdateTextures(RequestTextureCallback, GalShaderType.TessControl);
|
||||
UpdateTextures(RequestTextureCallback, GalShaderType.TessEvaluation);
|
||||
UpdateTextures(RequestTextureCallback, GalShaderType.Geometry);
|
||||
UpdateTextures(RequestTextureCallback, GalShaderType.Fragment);
|
||||
}
|
||||
|
||||
private void UpdateTextures(Func<int, GalShaderType, GalTexture> RequestTextureCallback, GalShaderType ShaderType)
|
||||
{
|
||||
foreach (ShaderDeclInfo DeclInfo in Shader.GetTextureUsage(ShaderType))
|
||||
{
|
||||
GalTexture Texture = RequestTextureCallback(DeclInfo.Index, ShaderType);
|
||||
|
||||
GL.ActiveTexture(TextureUnit.Texture0 + CurrentTextureIndex);
|
||||
|
||||
UploadTexture(Texture);
|
||||
|
||||
int Location = GL.GetUniformLocation(Shader.CurrentProgramHandle, DeclInfo.Name);
|
||||
|
||||
GL.Uniform1(Location, CurrentTextureIndex++);
|
||||
}
|
||||
}
|
||||
|
||||
private void UploadTexture(GalTexture Texture)
|
||||
{
|
||||
int Handle = EnsureTextureInitialized(CurrentTextureIndex);
|
||||
|
||||
GL.BindTexture(TextureTarget.Texture2D, Handle);
|
||||
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.Repeat);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.Repeat);
|
||||
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
|
||||
|
||||
const PixelInternalFormat Pif = PixelInternalFormat.Rgba;
|
||||
|
||||
int W = Texture.Width;
|
||||
int H = Texture.Height;
|
||||
|
||||
const PixelFormat Pf = PixelFormat.Rgba;
|
||||
|
||||
const PixelType Pt = PixelType.UnsignedByte;
|
||||
|
||||
byte[] Buffer = TextureDecoder.Decode(Texture);
|
||||
|
||||
GL.TexImage2D(TextureTarget.Texture2D, 0, Pif, W, H, 0, Pf, Pt, Buffer);
|
||||
}
|
||||
|
||||
private int EnsureTextureInitialized(int TextureIndex)
|
||||
{
|
||||
int Handle = Textures[TextureIndex];
|
||||
|
||||
if (Handle == 0)
|
||||
{
|
||||
Handle = Textures[TextureIndex] = GL.GenTexture();
|
||||
}
|
||||
|
||||
return Handle;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
using OpenTK;
|
||||
using OpenTK.Graphics.OpenGL;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
|
@ -7,29 +6,24 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
{
|
||||
public class OpenGLRenderer : IGalRenderer
|
||||
{
|
||||
private struct Texture
|
||||
{
|
||||
public int Handle;
|
||||
}
|
||||
|
||||
private Texture[] Textures;
|
||||
|
||||
private OGLRasterizer Rasterizer;
|
||||
|
||||
private OGLShader Shader;
|
||||
|
||||
private OGLTexture Texture;
|
||||
|
||||
private ConcurrentQueue<Action> ActionsQueue;
|
||||
|
||||
private FrameBuffer FbRenderer;
|
||||
|
||||
public OpenGLRenderer()
|
||||
{
|
||||
Textures = new Texture[8];
|
||||
|
||||
Rasterizer = new OGLRasterizer();
|
||||
|
||||
Shader = new OGLShader();
|
||||
|
||||
Texture = new OGLTexture(Shader);
|
||||
|
||||
ActionsQueue = new ConcurrentQueue<Action>();
|
||||
}
|
||||
|
||||
|
@ -116,33 +110,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
ActionsQueue.Enqueue(() => Rasterizer.RenderVertexArray(VbIndex));
|
||||
}
|
||||
|
||||
public void SendR8G8B8A8Texture(int Index, byte[] Buffer, int Width, int Height)
|
||||
{
|
||||
EnsureTexInitialized(Index);
|
||||
|
||||
GL.BindTexture(TextureTarget.Texture2D, Textures[Index].Handle);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.Repeat);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.Repeat);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
|
||||
GL.TexImage2D(TextureTarget.Texture2D,
|
||||
0,
|
||||
PixelInternalFormat.Rgba,
|
||||
Width,
|
||||
Height,
|
||||
0,
|
||||
PixelFormat.Rgba,
|
||||
PixelType.UnsignedByte,
|
||||
Buffer);
|
||||
}
|
||||
|
||||
public void BindTexture(int Index)
|
||||
{
|
||||
GL.ActiveTexture(TextureUnit.Texture0 + Index);
|
||||
|
||||
GL.BindTexture(TextureTarget.Texture2D, Textures[Index].Handle);
|
||||
}
|
||||
|
||||
public void CreateShader(long Tag, GalShaderType Type, byte[] Data)
|
||||
{
|
||||
if (Data == null)
|
||||
|
@ -153,7 +120,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
ActionsQueue.Enqueue(() => Shader.Create(Tag, Type, Data));
|
||||
}
|
||||
|
||||
public void SetShaderCb(long Tag, int Cbuf, byte[] Data)
|
||||
public void SetShaderConstBuffer(long Tag, int Cbuf, byte[] Data)
|
||||
{
|
||||
if (Data == null)
|
||||
{
|
||||
|
@ -173,16 +140,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
ActionsQueue.Enqueue(() => Shader.BindProgram());
|
||||
}
|
||||
|
||||
private void EnsureTexInitialized(int TexIndex)
|
||||
public void UpdateTextures(Func<int, GalShaderType, GalTexture> RequestTextureCallback)
|
||||
{
|
||||
Texture Tex = Textures[TexIndex];
|
||||
|
||||
if (Tex.Handle == 0)
|
||||
{
|
||||
Tex.Handle = GL.GenTexture();
|
||||
}
|
||||
|
||||
Textures[TexIndex] = Tex;
|
||||
ActionsQueue.Enqueue(() => Texture.UpdateTextures(RequestTextureCallback));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -112,7 +112,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
string Name = StagePrefix + TextureName + Index;
|
||||
|
||||
m_Textures.TryAdd(Handle, new ShaderDeclInfo(Name, Index));
|
||||
m_Textures.TryAdd(Handle, new ShaderDeclInfo(Name, Handle));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -282,7 +282,8 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
throw new NotImplementedException(Op.Inst.ToString());
|
||||
}
|
||||
|
||||
if (!(Entry || IsUnary(Op.Inst)))
|
||||
if (!Entry && (Op.OperandB != null ||
|
||||
Op.OperandC != null))
|
||||
{
|
||||
Expr = "(" + Expr + ")";
|
||||
}
|
||||
|
@ -293,24 +294,6 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
}
|
||||
}
|
||||
|
||||
private bool IsUnary(ShaderIrInst Inst)
|
||||
{
|
||||
return Inst == ShaderIrInst.Bnot ||
|
||||
Inst == ShaderIrInst.Fabs ||
|
||||
Inst == ShaderIrInst.Fcos ||
|
||||
Inst == ShaderIrInst.Fex2 ||
|
||||
Inst == ShaderIrInst.Flg2 ||
|
||||
Inst == ShaderIrInst.Fneg ||
|
||||
Inst == ShaderIrInst.Frcp ||
|
||||
Inst == ShaderIrInst.Frsq ||
|
||||
Inst == ShaderIrInst.Fsin ||
|
||||
Inst == ShaderIrInst.Ipa ||
|
||||
Inst == ShaderIrInst.Texr ||
|
||||
Inst == ShaderIrInst.Texg ||
|
||||
Inst == ShaderIrInst.Texb ||
|
||||
Inst == ShaderIrInst.Texa;
|
||||
}
|
||||
|
||||
private string GetName(ShaderIrOperCbuf Cbuf)
|
||||
{
|
||||
if (!Decl.Uniforms.TryGetValue((Cbuf.Index, Cbuf.Offs), out ShaderDeclInfo DeclInfo))
|
||||
|
@ -331,12 +314,12 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
return GetName(Decl.InAttributes, Abuf);
|
||||
}
|
||||
|
||||
private string GetName(IReadOnlyDictionary<int, ShaderDeclInfo> Decls, ShaderIrOperAbuf Abuf)
|
||||
private string GetName(IReadOnlyDictionary<int, ShaderDeclInfo> Dict, ShaderIrOperAbuf Abuf)
|
||||
{
|
||||
int Index = Abuf.Offs >> 4;
|
||||
int Elem = (Abuf.Offs >> 2) & 3;
|
||||
|
||||
if (!Decls.TryGetValue(Index, out ShaderDeclInfo DeclInfo))
|
||||
if (!Dict.TryGetValue(Index, out ShaderDeclInfo DeclInfo))
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
@ -359,11 +342,11 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
return Pred.IsConst ? "true" : GetNameWithSwizzle(Decl.Preds, Pred.Index);
|
||||
}
|
||||
|
||||
private string GetNameWithSwizzle(IReadOnlyDictionary<int, ShaderDeclInfo> Decls, int Index)
|
||||
private string GetNameWithSwizzle(IReadOnlyDictionary<int, ShaderDeclInfo> Dict, int Index)
|
||||
{
|
||||
int VecIndex = Index >> 2;
|
||||
|
||||
if (Decls.TryGetValue(VecIndex, out ShaderDeclInfo DeclInfo))
|
||||
if (Dict.TryGetValue(VecIndex, out ShaderDeclInfo DeclInfo))
|
||||
{
|
||||
if (DeclInfo.Size > 1 && Index < VecIndex + DeclInfo.Size)
|
||||
{
|
||||
|
@ -371,7 +354,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
}
|
||||
}
|
||||
|
||||
if (!Decls.TryGetValue(Index, out DeclInfo))
|
||||
if (!Dict.TryGetValue(Index, out DeclInfo))
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
@ -385,6 +368,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
}
|
||||
|
||||
private string GetBandExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "&&");
|
||||
|
||||
private string GetBnotExpr(ShaderIrOp Op) => GetUnaryExpr(Op, "!");
|
||||
|
||||
private string GetCltExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "<");
|
||||
|
@ -471,9 +455,8 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
private string GetTexSamplerCoords(ShaderIrOp Op)
|
||||
{
|
||||
return "vec2(" +
|
||||
GetInOperName(Op.OperandA) + ", " +
|
||||
GetInOperName(Op.OperandB) + ")";
|
||||
return "vec2(" + GetInOperName(Op.OperandA, Entry: true) + ", " +
|
||||
GetInOperName(Op.OperandB, Entry: true) + ")";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,14 +1,14 @@
|
|||
using System;
|
||||
using System.Drawing;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu
|
||||
namespace Ryujinx.Graphics.Gal.Texture
|
||||
{
|
||||
static class BCn
|
||||
{
|
||||
public static byte[] DecodeBC1(NsGpuTexture Tex, int Offset)
|
||||
public static byte[] DecodeBC1(GalTexture Texture, int Offset)
|
||||
{
|
||||
int W = (Tex.Width + 3) / 4;
|
||||
int H = (Tex.Height + 3) / 4;
|
||||
int W = (Texture.Width + 3) / 4;
|
||||
int H = (Texture.Height + 3) / 4;
|
||||
|
||||
byte[] Output = new byte[W * H * 64];
|
||||
|
||||
|
@ -20,7 +20,7 @@ namespace Ryujinx.Graphics.Gpu
|
|||
{
|
||||
int IOffs = Offset + Swizzle.GetSwizzledAddress64(X, Y) * 8;
|
||||
|
||||
byte[] Tile = BCnDecodeTile(Tex.Data, IOffs, true);
|
||||
byte[] Tile = BCnDecodeTile(Texture.Data, IOffs, true);
|
||||
|
||||
int TOffset = 0;
|
||||
|
||||
|
@ -44,10 +44,10 @@ namespace Ryujinx.Graphics.Gpu
|
|||
return Output;
|
||||
}
|
||||
|
||||
public static byte[] DecodeBC2(NsGpuTexture Tex, int Offset)
|
||||
public static byte[] DecodeBC2(GalTexture Texture, int Offset)
|
||||
{
|
||||
int W = (Tex.Width + 3) / 4;
|
||||
int H = (Tex.Height + 3) / 4;
|
||||
int W = (Texture.Width + 3) / 4;
|
||||
int H = (Texture.Height + 3) / 4;
|
||||
|
||||
byte[] Output = new byte[W * H * 64];
|
||||
|
||||
|
@ -59,10 +59,10 @@ namespace Ryujinx.Graphics.Gpu
|
|||
{
|
||||
int IOffs = Offset + Swizzle.GetSwizzledAddress128(X, Y) * 16;
|
||||
|
||||
byte[] Tile = BCnDecodeTile(Tex.Data, IOffs + 8, false);
|
||||
byte[] Tile = BCnDecodeTile(Texture.Data, IOffs + 8, false);
|
||||
|
||||
int AlphaLow = Get32(Tex.Data, IOffs + 0);
|
||||
int AlphaHigh = Get32(Tex.Data, IOffs + 4);
|
||||
int AlphaLow = Get32(Texture.Data, IOffs + 0);
|
||||
int AlphaHigh = Get32(Texture.Data, IOffs + 4);
|
||||
|
||||
ulong AlphaCh = (uint)AlphaLow | (ulong)AlphaHigh << 32;
|
||||
|
||||
|
@ -90,10 +90,10 @@ namespace Ryujinx.Graphics.Gpu
|
|||
return Output;
|
||||
}
|
||||
|
||||
public static byte[] DecodeBC3(NsGpuTexture Tex, int Offset)
|
||||
public static byte[] DecodeBC3(GalTexture Texture, int Offset)
|
||||
{
|
||||
int W = (Tex.Width + 3) / 4;
|
||||
int H = (Tex.Height + 3) / 4;
|
||||
int W = (Texture.Width + 3) / 4;
|
||||
int H = (Texture.Height + 3) / 4;
|
||||
|
||||
byte[] Output = new byte[W * H * 64];
|
||||
|
||||
|
@ -105,17 +105,17 @@ namespace Ryujinx.Graphics.Gpu
|
|||
{
|
||||
int IOffs = Offset + Swizzle.GetSwizzledAddress128(X, Y) * 16;
|
||||
|
||||
byte[] Tile = BCnDecodeTile(Tex.Data, IOffs + 8, false);
|
||||
byte[] Tile = BCnDecodeTile(Texture.Data, IOffs + 8, false);
|
||||
|
||||
byte[] Alpha = new byte[8];
|
||||
|
||||
Alpha[0] = Tex.Data[IOffs + 0];
|
||||
Alpha[1] = Tex.Data[IOffs + 1];
|
||||
Alpha[0] = Texture.Data[IOffs + 0];
|
||||
Alpha[1] = Texture.Data[IOffs + 1];
|
||||
|
||||
CalculateBC3Alpha(Alpha);
|
||||
|
||||
int AlphaLow = Get32(Tex.Data, IOffs + 2);
|
||||
int AlphaHigh = Get16(Tex.Data, IOffs + 6);
|
||||
int AlphaLow = Get32(Texture.Data, IOffs + 2);
|
||||
int AlphaHigh = Get16(Texture.Data, IOffs + 6);
|
||||
|
||||
ulong AlphaCh = (uint)AlphaLow | (ulong)AlphaHigh << 32;
|
||||
|
||||
|
@ -143,10 +143,10 @@ namespace Ryujinx.Graphics.Gpu
|
|||
return Output;
|
||||
}
|
||||
|
||||
public static byte[] DecodeBC4(NsGpuTexture Tex, int Offset)
|
||||
public static byte[] DecodeBC4(GalTexture Texture, int Offset)
|
||||
{
|
||||
int W = (Tex.Width + 3) / 4;
|
||||
int H = (Tex.Height + 3) / 4;
|
||||
int W = (Texture.Width + 3) / 4;
|
||||
int H = (Texture.Height + 3) / 4;
|
||||
|
||||
byte[] Output = new byte[W * H * 64];
|
||||
|
||||
|
@ -160,13 +160,13 @@ namespace Ryujinx.Graphics.Gpu
|
|||
|
||||
byte[] Red = new byte[8];
|
||||
|
||||
Red[0] = Tex.Data[IOffs + 0];
|
||||
Red[1] = Tex.Data[IOffs + 1];
|
||||
Red[0] = Texture.Data[IOffs + 0];
|
||||
Red[1] = Texture.Data[IOffs + 1];
|
||||
|
||||
CalculateBC3Alpha(Red);
|
||||
|
||||
int RedLow = Get32(Tex.Data, IOffs + 2);
|
||||
int RedHigh = Get16(Tex.Data, IOffs + 6);
|
||||
int RedLow = Get32(Texture.Data, IOffs + 2);
|
||||
int RedHigh = Get16(Texture.Data, IOffs + 6);
|
||||
|
||||
ulong RedCh = (uint)RedLow | (ulong)RedHigh << 32;
|
||||
|
||||
|
@ -194,10 +194,10 @@ namespace Ryujinx.Graphics.Gpu
|
|||
return Output;
|
||||
}
|
||||
|
||||
public static byte[] DecodeBC5(NsGpuTexture Tex, int Offset, bool SNorm)
|
||||
public static byte[] DecodeBC5(GalTexture Texture, int Offset, bool SNorm)
|
||||
{
|
||||
int W = (Tex.Width + 3) / 4;
|
||||
int H = (Tex.Height + 3) / 4;
|
||||
int W = (Texture.Width + 3) / 4;
|
||||
int H = (Texture.Height + 3) / 4;
|
||||
|
||||
byte[] Output = new byte[W * H * 64];
|
||||
|
||||
|
@ -212,11 +212,11 @@ namespace Ryujinx.Graphics.Gpu
|
|||
byte[] Red = new byte[8];
|
||||
byte[] Green = new byte[8];
|
||||
|
||||
Red[0] = Tex.Data[IOffs + 0];
|
||||
Red[1] = Tex.Data[IOffs + 1];
|
||||
Red[0] = Texture.Data[IOffs + 0];
|
||||
Red[1] = Texture.Data[IOffs + 1];
|
||||
|
||||
Green[0] = Tex.Data[IOffs + 8];
|
||||
Green[1] = Tex.Data[IOffs + 9];
|
||||
Green[0] = Texture.Data[IOffs + 8];
|
||||
Green[1] = Texture.Data[IOffs + 9];
|
||||
|
||||
if (SNorm)
|
||||
{
|
||||
|
@ -229,11 +229,11 @@ namespace Ryujinx.Graphics.Gpu
|
|||
CalculateBC3Alpha(Green);
|
||||
}
|
||||
|
||||
int RedLow = Get32(Tex.Data, IOffs + 2);
|
||||
int RedHigh = Get16(Tex.Data, IOffs + 6);
|
||||
int RedLow = Get32(Texture.Data, IOffs + 2);
|
||||
int RedHigh = Get16(Texture.Data, IOffs + 6);
|
||||
|
||||
int GreenLow = Get32(Tex.Data, IOffs + 10);
|
||||
int GreenHigh = Get16(Tex.Data, IOffs + 14);
|
||||
int GreenLow = Get32(Texture.Data, IOffs + 10);
|
||||
int GreenHigh = Get16(Texture.Data, IOffs + 14);
|
||||
|
||||
ulong RedCh = (uint)RedLow | (ulong)RedHigh << 32;
|
||||
ulong GreenCh = (uint)GreenLow | (ulong)GreenHigh << 32;
|
|
@ -1,6 +1,6 @@
|
|||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu
|
||||
namespace Ryujinx.Graphics.Gal.Texture
|
||||
{
|
||||
class SwizzleAddr
|
||||
{
|
||||
|
@ -109,7 +109,7 @@ namespace Ryujinx.Graphics.Gpu
|
|||
* y x x x x x x y y y y x y y x y 0 0 0 0 1024 x 1024 dxt5
|
||||
* y y x x x x x x y y y y x y y x y x 0 0 0 2048 x 2048 dxt1
|
||||
* y y y x x x x x x y y y y x y y x y x x 0 0 1024 x 1024 rgba8888
|
||||
*
|
||||
*
|
||||
* Read from right to left, LSB first.
|
||||
*/
|
||||
int XCnt = XBase;
|
19
Ryujinx.Graphics/Gal/Texture/TextureDecoder.cs
Normal file
19
Ryujinx.Graphics/Gal/Texture/TextureDecoder.cs
Normal file
|
@ -0,0 +1,19 @@
|
|||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Gal.Texture
|
||||
{
|
||||
static class TextureDecoder
|
||||
{
|
||||
public static byte[] Decode(GalTexture Texture)
|
||||
{
|
||||
switch (Texture.Format)
|
||||
{
|
||||
case GalTextureFormat.BC1: return BCn.DecodeBC1(Texture, 0);
|
||||
case GalTextureFormat.BC2: return BCn.DecodeBC2(Texture, 0);
|
||||
case GalTextureFormat.BC3: return BCn.DecodeBC3(Texture, 0);
|
||||
}
|
||||
|
||||
throw new NotImplementedException(Texture.Format.ToString());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
namespace Ryujinx.Graphics.Gpu
|
||||
{
|
||||
struct NsGpuTexture
|
||||
{
|
||||
public int Width;
|
||||
public int Height;
|
||||
|
||||
public byte[] Data;
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
namespace Ryujinx.Graphics.Gpu
|
||||
{
|
||||
enum NsGpuTextureFormat
|
||||
{
|
||||
BC1 = 0x24,
|
||||
BC2 = 0x25,
|
||||
BC3 = 0x26
|
||||
}
|
||||
}
|
|
@ -71,6 +71,7 @@ namespace Ryujinx.Graphics.Gpu
|
|||
|
||||
Gpu.Renderer.BindProgram();
|
||||
|
||||
UploadTextures(Memory);
|
||||
UploadUniforms(Memory);
|
||||
UploadVertexArrays(Memory);
|
||||
}
|
||||
|
@ -95,7 +96,10 @@ namespace Ryujinx.Graphics.Gpu
|
|||
int Control = ReadRegister(NvGpuEngine3dReg.ShaderNControl + Index * 0x10);
|
||||
int Offset = ReadRegister(NvGpuEngine3dReg.ShaderNOffset + Index * 0x10);
|
||||
|
||||
if (Offset == 0 || (Index != 1 && Index != 5))
|
||||
//Note: Vertex Program (B) is always enabled.
|
||||
bool Enable = (Control & 1) != 0 || Index == 1;
|
||||
|
||||
if (!Enable)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
@ -104,11 +108,6 @@ namespace Ryujinx.Graphics.Gpu
|
|||
|
||||
long Position = Gpu.GetCpuAddr(Tag);
|
||||
|
||||
if (Position == -1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
//TODO: Find a better way to calculate the size.
|
||||
int Size = 0x20000;
|
||||
|
||||
|
@ -127,11 +126,13 @@ namespace Ryujinx.Graphics.Gpu
|
|||
|
||||
for (int Index = 0; Index < 5; Index++)
|
||||
{
|
||||
int Offset = ReadRegister(NvGpuEngine3dReg.ShaderNOffset + (Index + 1) * 0x10);
|
||||
int Control = ReadRegister(NvGpuEngine3dReg.ShaderNControl + (Index + 1) * 0x10);
|
||||
int Offset = ReadRegister(NvGpuEngine3dReg.ShaderNOffset + (Index + 1) * 0x10);
|
||||
|
||||
long Tag = BasePosition + (uint)Offset;
|
||||
//Note: Vertex Program (B) is always enabled.
|
||||
bool Enable = (Control & 1) != 0 || Index == 0;
|
||||
|
||||
if (Offset == 0 || (Index != 0 && Index != 4))
|
||||
if (!Enable)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
@ -146,7 +147,7 @@ namespace Ryujinx.Graphics.Gpu
|
|||
|
||||
byte[] Data = AMemoryHelper.ReadBytes(Memory, CbPosition, (uint)Cb.Size);
|
||||
|
||||
Gpu.Renderer.SetShaderCb(Tag, Cbuf, Data);
|
||||
Gpu.Renderer.SetShaderConstBuffer(BasePosition + (uint)Offset, Cbuf, Data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -204,6 +205,78 @@ namespace Ryujinx.Graphics.Gpu
|
|||
}
|
||||
}
|
||||
|
||||
private void UploadTextures(AMemory Memory)
|
||||
{
|
||||
int TextureCbIndex = ReadRegister(NvGpuEngine3dReg.TextureCbIndex);
|
||||
|
||||
long BasePosition = Cbs[TextureCbIndex].Position;
|
||||
|
||||
long Size = (uint)Cbs[TextureCbIndex].Size;
|
||||
|
||||
Gpu.Renderer.UpdateTextures((int Index, GalShaderType ShaderType) =>
|
||||
{
|
||||
long Position = BasePosition + (int)ShaderType * Size;
|
||||
|
||||
return TextureRequestHandler(Memory, Position, Index);
|
||||
});
|
||||
}
|
||||
|
||||
private GalTexture TextureRequestHandler(AMemory Memory, long BasePosition, int Index)
|
||||
{
|
||||
long Position = BasePosition + Index * 4;
|
||||
|
||||
int TextureHandle = Memory.ReadInt32(Position);
|
||||
|
||||
int TicIndex = (TextureHandle >> 0) & 0xfffff;
|
||||
int TscIndex = (TextureHandle >> 20) & 0xfff;
|
||||
|
||||
TryGetCpuAddr(NvGpuEngine3dReg.TexHeaderPoolOffset, out long TicPosition);
|
||||
|
||||
int[] Tic = ReadWords(Memory, TicPosition + TicIndex * 0x20, 8);
|
||||
|
||||
GalTextureFormat Format = (GalTextureFormat)(Tic[0] & 0x7f);
|
||||
|
||||
long TextureAddress = (uint)Tic[1];
|
||||
|
||||
TextureAddress |= (long)((ushort)Tic[2]) << 32;
|
||||
|
||||
TextureAddress = Gpu.GetCpuAddr(TextureAddress);
|
||||
|
||||
int Width = (Tic[4] & 0xffff) + 1;
|
||||
int Height = (Tic[5] & 0xffff) + 1;
|
||||
|
||||
long TextureSize = GetTextureSize(Width, Height, Format);
|
||||
|
||||
byte[] Data = AMemoryHelper.ReadBytes(Memory, TextureAddress, TextureSize);
|
||||
|
||||
return new GalTexture(Data, Width, Height, Format);
|
||||
}
|
||||
|
||||
private long GetTextureSize(int Width, int Height, GalTextureFormat Format)
|
||||
{
|
||||
switch (Format)
|
||||
{
|
||||
case GalTextureFormat.A8B8G8R8: return (Width * Height) << 2;
|
||||
case GalTextureFormat.BC1: return (Width * Height) >> 1;
|
||||
case GalTextureFormat.BC2: return Width * Height;
|
||||
case GalTextureFormat.BC3: return Width * Height;
|
||||
}
|
||||
|
||||
throw new NotImplementedException(Format.ToString());
|
||||
}
|
||||
|
||||
private int[] ReadWords(AMemory Memory, long Position, int Count)
|
||||
{
|
||||
int[] Words = new int[Count];
|
||||
|
||||
for (int Index = 0; Index < Count; Index++, Position += 4)
|
||||
{
|
||||
Words[Index] = Memory.ReadInt32(Position);
|
||||
}
|
||||
|
||||
return Words;
|
||||
}
|
||||
|
||||
private static GalShaderType GetTypeFromProgram(int Program)
|
||||
{
|
||||
switch (Program)
|
||||
|
@ -267,7 +340,8 @@ namespace Ryujinx.Graphics.Gpu
|
|||
{
|
||||
Cbs[Index].Position = Position;
|
||||
Cbs[Index].Enabled = Enabled;
|
||||
Cbs[Index].Size = ReadRegister(NvGpuEngine3dReg.ConstBufferNSize);
|
||||
|
||||
Cbs[Index].Size = ReadRegister(NvGpuEngine3dReg.ConstBufferNSize);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ namespace Ryujinx.Graphics.Gpu
|
|||
enum NvGpuEngine3dReg
|
||||
{
|
||||
VertexAttribNFormat = 0x458,
|
||||
TexHeaderPoolOffset = 0x55d,
|
||||
ShaderAddress = 0x582,
|
||||
QueryAddress = 0x6c0,
|
||||
QuerySequence = 0x6c2,
|
||||
|
|
|
@ -141,6 +141,11 @@ namespace Ryujinx.Graphics.Gpu
|
|||
{
|
||||
case NvGpuEngine._3d: Call3dMethod(Memory, PBEntry); break;
|
||||
}
|
||||
|
||||
if (PBEntry.SubChannel > 4)
|
||||
{
|
||||
throw new System.Exception("bad subch");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue