Started to implement texture decoding on the GAL

This commit is contained in:
gdkchan 2018-04-01 21:51:22 -03:00
parent 5222708e37
commit 9da58cc655
16 changed files with 310 additions and 148 deletions

View 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;
}
}
}

View file

@ -0,0 +1,10 @@
namespace Ryujinx.Graphics.Gal
{
public enum GalTextureFormat
{
A8B8G8R8 = 0x8,
BC1 = 0x24,
BC2 = 0x25,
BC3 = 0x26
}
}

View file

@ -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);
}
}

View file

@ -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))

View 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;
}
}
}

View file

@ -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));
}
}
}

View file

@ -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;
}

View file

@ -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) + ")";
}
}
}

View file

@ -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;

View file

@ -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;

View 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());
}
}
}

View file

@ -1,10 +0,0 @@
namespace Ryujinx.Graphics.Gpu
{
struct NsGpuTexture
{
public int Width;
public int Height;
public byte[] Data;
}
}

View file

@ -1,9 +0,0 @@
namespace Ryujinx.Graphics.Gpu
{
enum NsGpuTextureFormat
{
BC1 = 0x24,
BC2 = 0x25,
BC3 = 0x26
}
}

View file

@ -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);
}
}

View file

@ -3,6 +3,7 @@ namespace Ryujinx.Graphics.Gpu
enum NvGpuEngine3dReg
{
VertexAttribNFormat = 0x458,
TexHeaderPoolOffset = 0x55d,
ShaderAddress = 0x582,
QueryAddress = 0x6c0,
QuerySequence = 0x6c2,

View file

@ -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");
}
}
}