Add support for rendering raw frame buffer (again), remove shader optimization pass as its not worth the effort to maintain it currently
This commit is contained in:
parent
f39ced70c1
commit
120fa26392
17 changed files with 189 additions and 793 deletions
|
@ -2,6 +2,7 @@ using ChocolArm64.Memory;
|
|||
using Ryujinx.Core.OsHle.Handles;
|
||||
using Ryujinx.Core.OsHle.Services.Nv;
|
||||
using Ryujinx.Graphics.Gal;
|
||||
using Ryujinx.Graphics.Gpu;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
@ -63,13 +64,7 @@ namespace Ryujinx.Core.OsHle.Services.Android
|
|||
|
||||
private ManualResetEvent WaitBufferFree;
|
||||
|
||||
private object RenderQueueLock;
|
||||
|
||||
private int RenderQueueCount;
|
||||
|
||||
private bool NvFlingerDisposed;
|
||||
|
||||
private bool KeepRunning;
|
||||
private bool Disposed;
|
||||
|
||||
public NvFlinger(IGalRenderer Renderer, KEvent ReleaseEvent)
|
||||
{
|
||||
|
@ -92,10 +87,6 @@ namespace Ryujinx.Core.OsHle.Services.Android
|
|||
BufferQueue = new BufferEntry[0x40];
|
||||
|
||||
WaitBufferFree = new ManualResetEvent(false);
|
||||
|
||||
RenderQueueLock = new object();
|
||||
|
||||
KeepRunning = true;
|
||||
}
|
||||
|
||||
public long ProcessParcelRequest(ServiceCtx Context, byte[] ParcelData, int Code)
|
||||
|
@ -296,8 +287,6 @@ namespace Ryujinx.Core.OsHle.Services.Android
|
|||
|
||||
NvMapFb MapFb = (NvMapFb)INvDrvServices.NvMapsFb.GetData(Context.Process, 0);
|
||||
|
||||
Renderer.SetFrameBuffer(Map.GpuAddress);
|
||||
|
||||
long Address = Map.CpuAddress;
|
||||
|
||||
if (MapFb.HasBufferOffset(Slot))
|
||||
|
@ -369,41 +358,24 @@ namespace Ryujinx.Core.OsHle.Services.Android
|
|||
Rotate = -MathF.PI * 0.5f;
|
||||
}
|
||||
|
||||
lock (RenderQueueLock)
|
||||
if (Context.Ns.Gpu.Engine3d.IsFrameBufferPosition(Map.GpuAddress))
|
||||
{
|
||||
if (NvFlingerDisposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
//Frame buffer is rendered to by the GPU, we can just
|
||||
//bind the frame buffer texture, it's not necessary to read anything.
|
||||
Renderer.SetFrameBuffer(Map.GpuAddress);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Frame buffer is not set on the GPU registers, in this case
|
||||
//assume that the app is manually writing to it.
|
||||
Texture Texture = new Texture(Address, FbWidth, FbHeight);
|
||||
|
||||
Interlocked.Increment(ref RenderQueueCount);
|
||||
byte[] Data = TextureReader.Read(Context.Memory, Texture);
|
||||
|
||||
Renderer.SetFrameBuffer(Data, FbWidth, FbHeight);
|
||||
}
|
||||
|
||||
byte* Fb = (byte*)Context.Memory.Ram + Address;
|
||||
|
||||
Context.Ns.Gpu.Renderer.QueueAction(delegate()
|
||||
{
|
||||
Context.Ns.Gpu.Renderer.SetFrameBuffer(
|
||||
Fb,
|
||||
FbWidth,
|
||||
FbHeight,
|
||||
ScaleX,
|
||||
ScaleY,
|
||||
OffsX,
|
||||
OffsY,
|
||||
Rotate);
|
||||
|
||||
BufferQueue[Slot].State = BufferState.Free;
|
||||
|
||||
Interlocked.Decrement(ref RenderQueueCount);
|
||||
|
||||
ReleaseEvent.Handle.Set();
|
||||
|
||||
lock (WaitBufferFree)
|
||||
{
|
||||
WaitBufferFree.Set();
|
||||
}
|
||||
});
|
||||
Context.Ns.Gpu.Renderer.QueueAction(() => ReleaseBuffer(Slot));
|
||||
}
|
||||
|
||||
private NvMap GetNvMap(ServiceCtx Context, int Slot)
|
||||
|
@ -422,6 +394,18 @@ namespace Ryujinx.Core.OsHle.Services.Android
|
|||
return INvDrvServices.NvMaps.GetData<NvMap>(Context.Process, NvMapHandle);
|
||||
}
|
||||
|
||||
private void ReleaseBuffer(int Slot)
|
||||
{
|
||||
BufferQueue[Slot].State = BufferState.Free;
|
||||
|
||||
ReleaseEvent.Handle.Set();
|
||||
|
||||
lock (WaitBufferFree)
|
||||
{
|
||||
WaitBufferFree.Set();
|
||||
}
|
||||
}
|
||||
|
||||
private int GetFreeSlotBlocking(int Width, int Height)
|
||||
{
|
||||
int Slot;
|
||||
|
@ -437,7 +421,7 @@ namespace Ryujinx.Core.OsHle.Services.Android
|
|||
|
||||
Logging.Debug("Waiting for a free BufferQueue slot...");
|
||||
|
||||
if (!KeepRunning)
|
||||
if (Disposed)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
@ -447,7 +431,7 @@ namespace Ryujinx.Core.OsHle.Services.Android
|
|||
|
||||
WaitBufferFree.WaitOne();
|
||||
}
|
||||
while (KeepRunning);
|
||||
while (!Disposed);
|
||||
|
||||
Logging.Debug($"Found free BufferQueue slot {Slot}!");
|
||||
|
||||
|
@ -487,26 +471,12 @@ namespace Ryujinx.Core.OsHle.Services.Android
|
|||
|
||||
protected virtual void Dispose(bool Disposing)
|
||||
{
|
||||
if (Disposing && !NvFlingerDisposed)
|
||||
if (Disposing && !Disposed)
|
||||
{
|
||||
lock (RenderQueueLock)
|
||||
{
|
||||
NvFlingerDisposed = true;
|
||||
}
|
||||
|
||||
//Ensure that all pending actions was sent before
|
||||
//we can safely assume that the class was disposed.
|
||||
while (RenderQueueCount > 0)
|
||||
{
|
||||
Thread.Yield();
|
||||
}
|
||||
|
||||
Renderer.ResetFrameBuffer();
|
||||
Disposed = true;
|
||||
|
||||
lock (WaitBufferFree)
|
||||
{
|
||||
KeepRunning = false;
|
||||
|
||||
WaitBufferFree.Set();
|
||||
}
|
||||
|
||||
|
|
|
@ -6,21 +6,12 @@ namespace Ryujinx.Graphics.Gal
|
|||
public unsafe interface IGalRenderer
|
||||
{
|
||||
void QueueAction(Action ActionMthd);
|
||||
|
||||
void RunActions();
|
||||
|
||||
void InitializeFrameBuffer();
|
||||
void ResetFrameBuffer();
|
||||
void Render();
|
||||
|
||||
void SetWindowSize(int Width, int Height);
|
||||
void SetFrameBuffer(
|
||||
byte* Fb,
|
||||
int Width,
|
||||
int Height,
|
||||
float ScaleX,
|
||||
float ScaleY,
|
||||
float OffsX,
|
||||
float OffsY,
|
||||
float Rotate);
|
||||
|
||||
//Blend
|
||||
void SetBlendEnable(bool Enable);
|
||||
|
@ -43,10 +34,12 @@ namespace Ryujinx.Graphics.Gal
|
|||
|
||||
void BindFrameBuffer(long Tag);
|
||||
|
||||
void BindFrameBufferTexture(long Tag, int Index);
|
||||
void BindFrameBufferTexture(long Tag, int Index, GalTextureSampler Sampler);
|
||||
|
||||
void SetFrameBuffer(long Tag);
|
||||
|
||||
void SetFrameBuffer(byte[] Data, int Width, int Height);
|
||||
|
||||
//Rasterizer
|
||||
void ClearBuffers(int RtIndex, GalClearBufferFlags Flags);
|
||||
|
||||
|
@ -72,10 +65,8 @@ namespace Ryujinx.Graphics.Gal
|
|||
void BindProgram();
|
||||
|
||||
//Texture
|
||||
void SetTexture(int Index, GalTexture Tex);
|
||||
void SetTextureAndSampler(int Index, GalTexture Texture, GalTextureSampler Sampler);
|
||||
|
||||
void BindTexture(int Index);
|
||||
|
||||
void SetSampler(GalTextureSampler Sampler);
|
||||
}
|
||||
}
|
|
@ -1,250 +0,0 @@
|
|||
using OpenTK;
|
||||
using OpenTK.Graphics.OpenGL;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Gal.OpenGL
|
||||
{
|
||||
unsafe class FrameBuffer
|
||||
{
|
||||
public int WindowWidth { get; set; }
|
||||
public int WindowHeight { get; set; }
|
||||
|
||||
private int VtxShaderHandle;
|
||||
private int FragShaderHandle;
|
||||
private int PrgShaderHandle;
|
||||
|
||||
private int TexHandle;
|
||||
private int TexWidth;
|
||||
private int TexHeight;
|
||||
|
||||
private int VaoHandle;
|
||||
private int VboHandle;
|
||||
|
||||
private int[] Pixels;
|
||||
|
||||
private byte* FbPtr;
|
||||
|
||||
private object FbPtrLock;
|
||||
|
||||
public FrameBuffer(int Width, int Height)
|
||||
{
|
||||
if (Width < 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(Width));
|
||||
}
|
||||
|
||||
if (Height < 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(Height));
|
||||
}
|
||||
|
||||
FbPtrLock = new object();
|
||||
|
||||
TexWidth = Width;
|
||||
TexHeight = Height;
|
||||
|
||||
WindowWidth = Width;
|
||||
WindowHeight = Height;
|
||||
|
||||
SetupShaders();
|
||||
SetupTexture();
|
||||
SetupVertex();
|
||||
}
|
||||
|
||||
private void SetupShaders()
|
||||
{
|
||||
VtxShaderHandle = GL.CreateShader(ShaderType.VertexShader);
|
||||
FragShaderHandle = GL.CreateShader(ShaderType.FragmentShader);
|
||||
|
||||
string VtxShaderSource = EmbeddedResource.GetString("GlFbVtxShader");
|
||||
string FragShaderSource = EmbeddedResource.GetString("GlFbFragShader");
|
||||
|
||||
GL.ShaderSource(VtxShaderHandle, VtxShaderSource);
|
||||
GL.ShaderSource(FragShaderHandle, FragShaderSource);
|
||||
GL.CompileShader(VtxShaderHandle);
|
||||
GL.CompileShader(FragShaderHandle);
|
||||
|
||||
PrgShaderHandle = GL.CreateProgram();
|
||||
|
||||
GL.AttachShader(PrgShaderHandle, VtxShaderHandle);
|
||||
GL.AttachShader(PrgShaderHandle, FragShaderHandle);
|
||||
GL.LinkProgram(PrgShaderHandle);
|
||||
GL.UseProgram(PrgShaderHandle);
|
||||
|
||||
int TexUniformLocation = GL.GetUniformLocation(PrgShaderHandle, "tex");
|
||||
|
||||
GL.Uniform1(TexUniformLocation, 0);
|
||||
|
||||
int WindowSizeUniformLocation = GL.GetUniformLocation(PrgShaderHandle, "window_size");
|
||||
|
||||
GL.Uniform2(WindowSizeUniformLocation, new Vector2(1280.0f, 720.0f));
|
||||
}
|
||||
|
||||
private void SetupTexture()
|
||||
{
|
||||
Pixels = new int[TexWidth * TexHeight];
|
||||
|
||||
if (TexHandle == 0)
|
||||
{
|
||||
TexHandle = GL.GenTexture();
|
||||
}
|
||||
|
||||
GL.BindTexture(TextureTarget.Texture2D, TexHandle);
|
||||
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,
|
||||
TexWidth,
|
||||
TexHeight,
|
||||
0,
|
||||
PixelFormat.Rgba,
|
||||
PixelType.UnsignedByte,
|
||||
IntPtr.Zero);
|
||||
}
|
||||
|
||||
private void SetupVertex()
|
||||
{
|
||||
VaoHandle = GL.GenVertexArray();
|
||||
VboHandle = GL.GenBuffer();
|
||||
|
||||
float[] Buffer = new float[]
|
||||
{
|
||||
-1, 1, 0, 0,
|
||||
1, 1, 1, 0,
|
||||
-1, -1, 0, 1,
|
||||
1, -1, 1, 1
|
||||
};
|
||||
|
||||
IntPtr Length = new IntPtr(Buffer.Length * 4);
|
||||
|
||||
GL.BindBuffer(BufferTarget.ArrayBuffer, VboHandle);
|
||||
GL.BufferData(BufferTarget.ArrayBuffer, Length, Buffer, BufferUsageHint.StreamDraw);
|
||||
GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
|
||||
|
||||
GL.BindVertexArray(VaoHandle);
|
||||
|
||||
GL.EnableVertexAttribArray(0);
|
||||
|
||||
GL.BindBuffer(BufferTarget.ArrayBuffer, VboHandle);
|
||||
|
||||
GL.VertexAttribPointer(0, 2, VertexAttribPointerType.Float, false, 16, 0);
|
||||
|
||||
GL.EnableVertexAttribArray(1);
|
||||
|
||||
GL.BindBuffer(BufferTarget.ArrayBuffer, VboHandle);
|
||||
|
||||
GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, 16, 8);
|
||||
|
||||
GL.BindVertexArray(0);
|
||||
}
|
||||
|
||||
public unsafe void Set(byte* Fb, int Width, int Height, Matrix2 Transform, Vector2 Offs)
|
||||
{
|
||||
if (Fb == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(Fb));
|
||||
}
|
||||
|
||||
if (Width < 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(Width));
|
||||
}
|
||||
|
||||
if (Height < 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(Height));
|
||||
}
|
||||
|
||||
lock (FbPtrLock)
|
||||
{
|
||||
FbPtr = Fb;
|
||||
}
|
||||
|
||||
if (Width != TexWidth ||
|
||||
Height != TexHeight)
|
||||
{
|
||||
TexWidth = Width;
|
||||
TexHeight = Height;
|
||||
|
||||
SetupTexture();
|
||||
}
|
||||
|
||||
GL.UseProgram(PrgShaderHandle);
|
||||
|
||||
int TransformUniformLocation = GL.GetUniformLocation(PrgShaderHandle, "transform");
|
||||
|
||||
GL.UniformMatrix2(TransformUniformLocation, false, ref Transform);
|
||||
|
||||
int WindowSizeUniformLocation = GL.GetUniformLocation(PrgShaderHandle, "window_size");
|
||||
|
||||
GL.Uniform2(WindowSizeUniformLocation, new Vector2(WindowWidth, WindowHeight));
|
||||
|
||||
int OffsetUniformLocation = GL.GetUniformLocation(PrgShaderHandle, "offset");
|
||||
|
||||
GL.Uniform2(OffsetUniformLocation, Offs);
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
lock (FbPtrLock)
|
||||
{
|
||||
FbPtr = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void Render()
|
||||
{
|
||||
lock (FbPtrLock)
|
||||
{
|
||||
if (FbPtr == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int Y = 0; Y < TexHeight; Y++)
|
||||
for (int X = 0; X < TexWidth; X++)
|
||||
{
|
||||
Pixels[X + Y * TexWidth] = *((int*)(FbPtr + GetSwizzleOffset(X, Y)));
|
||||
}
|
||||
}
|
||||
|
||||
GL.BindTexture(TextureTarget.Texture2D, TexHandle);
|
||||
GL.TexSubImage2D(TextureTarget.Texture2D,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
TexWidth,
|
||||
TexHeight,
|
||||
PixelFormat.Rgba,
|
||||
PixelType.UnsignedByte,
|
||||
Pixels);
|
||||
|
||||
GL.ActiveTexture(TextureUnit.Texture0);
|
||||
|
||||
GL.BindVertexArray(VaoHandle);
|
||||
|
||||
GL.UseProgram(PrgShaderHandle);
|
||||
|
||||
GL.DrawArrays(PrimitiveType.TriangleStrip, 0, 4);
|
||||
}
|
||||
|
||||
private int GetSwizzleOffset(int X, int Y)
|
||||
{
|
||||
int Pos;
|
||||
|
||||
Pos = (Y & 0x7f) >> 4;
|
||||
Pos += (X >> 4) << 3;
|
||||
Pos += (Y >> 7) * ((TexWidth >> 4) << 3);
|
||||
Pos *= 1024;
|
||||
Pos += ((Y & 0xf) >> 3) << 9;
|
||||
Pos += ((X & 0xf) >> 3) << 8;
|
||||
Pos += ((Y & 0x7) >> 1) << 6;
|
||||
Pos += ((X & 0x7) >> 2) << 5;
|
||||
Pos += ((Y & 0x1) >> 0) << 4;
|
||||
Pos += ((X & 0x3) >> 0) << 2;
|
||||
|
||||
return Pos;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -23,13 +23,13 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
private Dictionary<long, FrameBuffer> Fbs;
|
||||
|
||||
private FrameBuffer CurrentFb;
|
||||
|
||||
private ShaderProgram Shader;
|
||||
|
||||
private bool IsInitialized;
|
||||
|
||||
private int FbHandle;
|
||||
private int CurrFbHandle;
|
||||
private int CurrTexHandle;
|
||||
private int RawFbTexHandle;
|
||||
private int VaoHandle;
|
||||
private int VboHandle;
|
||||
|
||||
|
@ -47,12 +47,17 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
return;
|
||||
}
|
||||
|
||||
Width = 1280;
|
||||
Height = 720;
|
||||
|
||||
FrameBuffer Fb = new FrameBuffer();
|
||||
|
||||
Fb.Handle = GL.GenFramebuffer();
|
||||
Fb.Handle = GL.GenFramebuffer();
|
||||
Fb.RbHandle = GL.GenRenderbuffer();
|
||||
Fb.TexHandle = GL.GenTexture();
|
||||
|
||||
SetupTexture(Fb.TexHandle, Width, Height);
|
||||
|
||||
GL.BindFramebuffer(FramebufferTarget.Framebuffer, Fb.Handle);
|
||||
|
||||
GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, Fb.RbHandle);
|
||||
|
@ -60,8 +65,8 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
GL.RenderbufferStorage(
|
||||
RenderbufferTarget.Renderbuffer,
|
||||
RenderbufferStorage.Depth24Stencil8,
|
||||
1280,
|
||||
720);
|
||||
Width,
|
||||
Height);
|
||||
|
||||
GL.FramebufferRenderbuffer(
|
||||
FramebufferTarget.Framebuffer,
|
||||
|
@ -69,14 +74,11 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
RenderbufferTarget.Renderbuffer,
|
||||
Fb.RbHandle);
|
||||
|
||||
GL.BindTexture(TextureTarget.Texture2D, Fb.TexHandle);
|
||||
|
||||
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, 1280, 720, 0, PixelFormat.Rgba, PixelType.UnsignedByte, IntPtr.Zero);
|
||||
|
||||
GL.FramebufferTexture(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0, Fb.TexHandle, 0);
|
||||
GL.FramebufferTexture(
|
||||
FramebufferTarget.Framebuffer,
|
||||
FramebufferAttachment.ColorAttachment0,
|
||||
Fb.TexHandle,
|
||||
0);
|
||||
|
||||
GL.DrawBuffer(DrawBufferMode.ColorAttachment0);
|
||||
|
||||
|
@ -89,7 +91,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
{
|
||||
GL.BindFramebuffer(FramebufferTarget.Framebuffer, Fb.Handle);
|
||||
|
||||
FbHandle = Fb.Handle;
|
||||
CurrFbHandle = Fb.Handle;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -107,24 +109,39 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
{
|
||||
if (Fbs.TryGetValue(Tag, out FrameBuffer Fb))
|
||||
{
|
||||
CurrentFb = Fb;
|
||||
CurrTexHandle = Fb.TexHandle;
|
||||
}
|
||||
}
|
||||
|
||||
public void Set(byte[] Data, int Width, int Height)
|
||||
{
|
||||
EnsureInitialized();
|
||||
|
||||
GL.ActiveTexture(TextureUnit.Texture0);
|
||||
|
||||
GL.BindTexture(TextureTarget.Texture2D, RawFbTexHandle);
|
||||
|
||||
(PixelFormat Format, PixelType Type) = OGLEnumConverter.GetTextureFormat(GalTextureFormat.A8B8G8R8);
|
||||
|
||||
GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, 0, Width, Height, Format, Type, Data);
|
||||
|
||||
CurrTexHandle = RawFbTexHandle;
|
||||
}
|
||||
|
||||
public void Render()
|
||||
{
|
||||
if (CurrentFb.TexHandle != 0)
|
||||
if (CurrTexHandle != 0)
|
||||
{
|
||||
EnsureInitialized();
|
||||
|
||||
GL.ActiveTexture(TextureUnit.Texture0);
|
||||
|
||||
GL.BindTexture(TextureTarget.Texture2D, CurrTexHandle);
|
||||
|
||||
int CurrentProgram = GL.GetInteger(GetPName.CurrentProgram);
|
||||
|
||||
GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
|
||||
|
||||
GL.ActiveTexture(TextureUnit.Texture0);
|
||||
|
||||
GL.BindTexture(TextureTarget.Texture2D, CurrentFb.TexHandle);
|
||||
|
||||
GL.BindVertexArray(VaoHandle);
|
||||
|
||||
GL.UseProgram(Shader.Handle);
|
||||
|
@ -132,7 +149,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
GL.DrawArrays(PrimitiveType.TriangleStrip, 0, 4);
|
||||
|
||||
//Restore the original state.
|
||||
GL.BindFramebuffer(FramebufferTarget.Framebuffer, FbHandle);
|
||||
GL.BindFramebuffer(FramebufferTarget.Framebuffer, CurrFbHandle);
|
||||
|
||||
GL.UseProgram(CurrentProgram);
|
||||
}
|
||||
|
@ -146,6 +163,10 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
SetupShader();
|
||||
SetupVertex();
|
||||
|
||||
RawFbTexHandle = GL.GenTexture();
|
||||
|
||||
SetupTexture(RawFbTexHandle, 1280, 720);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -217,5 +238,32 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, 16, 8);
|
||||
}
|
||||
|
||||
private void SetupTexture(int Handle, int Width, int Height)
|
||||
{
|
||||
GL.BindTexture(TextureTarget.Texture2D, Handle);
|
||||
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
|
||||
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
|
||||
|
||||
(PixelFormat Format, PixelType Type) = OGLEnumConverter.GetTextureFormat(GalTextureFormat.A8B8G8R8);
|
||||
|
||||
const PixelInternalFormat InternalFmt = PixelInternalFormat.Rgba;
|
||||
|
||||
const int Level = 0;
|
||||
const int Border = 0;
|
||||
|
||||
GL.TexImage2D(
|
||||
TextureTarget.Texture2D,
|
||||
Level,
|
||||
InternalFmt,
|
||||
Width,
|
||||
Height,
|
||||
Border,
|
||||
Format,
|
||||
Type,
|
||||
IntPtr.Zero);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -17,6 +17,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
Bind(Index);
|
||||
|
||||
const int Level = 0; //TODO: Support mipmap textures.
|
||||
const int Border = 0;
|
||||
|
||||
if (IsCompressedTextureFormat(Texture.Format))
|
||||
|
@ -25,7 +26,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
GL.CompressedTexImage2D(
|
||||
TextureTarget.Texture2D,
|
||||
0,
|
||||
Level,
|
||||
InternalFmt,
|
||||
Texture.Width,
|
||||
Texture.Height,
|
||||
|
@ -37,17 +38,17 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
{
|
||||
const PixelInternalFormat InternalFmt = PixelInternalFormat.Rgba;
|
||||
|
||||
(PixelFormat, PixelType) Format = OGLEnumConverter.GetTextureFormat(Texture.Format);
|
||||
(PixelFormat Format, PixelType Type) = OGLEnumConverter.GetTextureFormat(Texture.Format);
|
||||
|
||||
GL.TexImage2D(
|
||||
TextureTarget.Texture2D,
|
||||
0,
|
||||
Level,
|
||||
InternalFmt,
|
||||
Texture.Width,
|
||||
Texture.Height,
|
||||
Border,
|
||||
Format.Item1,
|
||||
Format.Item2,
|
||||
Format,
|
||||
Type,
|
||||
Texture.Data);
|
||||
}
|
||||
}
|
||||
|
@ -59,7 +60,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
GL.BindTexture(TextureTarget.Texture2D, Handle);
|
||||
}
|
||||
|
||||
public void Set(GalTextureSampler Sampler)
|
||||
public static void Set(GalTextureSampler Sampler)
|
||||
{
|
||||
int WrapS = (int)OGLEnumConverter.GetTextureWrapMode(Sampler.AddressU);
|
||||
int WrapT = (int)OGLEnumConverter.GetTextureWrapMode(Sampler.AddressV);
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
using OpenTK;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
|
@ -19,8 +18,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
private ConcurrentQueue<Action> ActionsQueue;
|
||||
|
||||
private FrameBuffer FbRenderer;
|
||||
|
||||
public OpenGLRenderer()
|
||||
{
|
||||
Blend = new OGLBlend();
|
||||
|
@ -36,16 +33,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
ActionsQueue = new ConcurrentQueue<Action>();
|
||||
}
|
||||
|
||||
public void InitializeFrameBuffer()
|
||||
{
|
||||
FbRenderer = new FrameBuffer(1280, 720);
|
||||
}
|
||||
|
||||
public void ResetFrameBuffer()
|
||||
{
|
||||
FbRenderer.Reset();
|
||||
}
|
||||
|
||||
public void QueueAction(Action ActionMthd)
|
||||
{
|
||||
ActionsQueue.Enqueue(ActionMthd);
|
||||
|
@ -63,34 +50,12 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
public void Render()
|
||||
{
|
||||
//FbRenderer.Render();
|
||||
FrameBuffer.Render();
|
||||
}
|
||||
|
||||
public void SetWindowSize(int Width, int Height)
|
||||
{
|
||||
FbRenderer.WindowWidth = Width;
|
||||
FbRenderer.WindowHeight = Height;
|
||||
}
|
||||
|
||||
public unsafe void SetFrameBuffer(
|
||||
byte* Fb,
|
||||
int Width,
|
||||
int Height,
|
||||
float ScaleX,
|
||||
float ScaleY,
|
||||
float OffsX,
|
||||
float OffsY,
|
||||
float Rotate)
|
||||
{
|
||||
Matrix2 Transform;
|
||||
|
||||
Transform = Matrix2.CreateScale(ScaleX, ScaleY);
|
||||
Transform *= Matrix2.CreateRotation(Rotate);
|
||||
|
||||
Vector2 Offs = new Vector2(OffsX, OffsY);
|
||||
|
||||
FbRenderer.Set(Fb, Width, Height, Transform, Offs);
|
||||
//TODO
|
||||
}
|
||||
|
||||
public void SetBlendEnable(bool Enable)
|
||||
|
@ -143,9 +108,14 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
ActionsQueue.Enqueue(() => FrameBuffer.Bind(Tag));
|
||||
}
|
||||
|
||||
public void BindFrameBufferTexture(long Tag, int Index)
|
||||
public void BindFrameBufferTexture(long Tag, int Index, GalTextureSampler Sampler)
|
||||
{
|
||||
ActionsQueue.Enqueue(() => FrameBuffer.BindTexture(Tag, Index));
|
||||
ActionsQueue.Enqueue(() =>
|
||||
{
|
||||
FrameBuffer.BindTexture(Tag, Index);
|
||||
|
||||
OGLTexture.Set(Sampler);
|
||||
});
|
||||
}
|
||||
|
||||
public void SetFrameBuffer(long Tag)
|
||||
|
@ -153,6 +123,11 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
ActionsQueue.Enqueue(() => FrameBuffer.Set(Tag));
|
||||
}
|
||||
|
||||
public void SetFrameBuffer(byte[] Data, int Width, int Height)
|
||||
{
|
||||
ActionsQueue.Enqueue(() => FrameBuffer.Set(Data, Width, Height));
|
||||
}
|
||||
|
||||
public void ClearBuffers(int RtIndex, GalClearBufferFlags Flags)
|
||||
{
|
||||
ActionsQueue.Enqueue(() => Rasterizer.ClearBuffers(RtIndex, Flags));
|
||||
|
@ -245,19 +220,19 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
ActionsQueue.Enqueue(() => Shader.BindProgram());
|
||||
}
|
||||
|
||||
public void SetTexture(int Index, GalTexture Texture)
|
||||
public void SetTextureAndSampler(int Index, GalTexture Texture, GalTextureSampler Sampler)
|
||||
{
|
||||
ActionsQueue.Enqueue(() => this.Texture.Set(Index, Texture));
|
||||
ActionsQueue.Enqueue(() =>
|
||||
{
|
||||
this.Texture.Set(Index, Texture);
|
||||
|
||||
OGLTexture.Set(Sampler);
|
||||
});
|
||||
}
|
||||
|
||||
public void BindTexture(int Index)
|
||||
{
|
||||
ActionsQueue.Enqueue(() => Texture.Bind(Index));
|
||||
}
|
||||
|
||||
public void SetSampler(GalTextureSampler Sampler)
|
||||
{
|
||||
ActionsQueue.Enqueue(() => Texture.Set(Sampler));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -81,7 +81,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
public GlslProgram Decompile(int[] Code, GalShaderType ShaderType)
|
||||
{
|
||||
ShaderIrBlock Block = ShaderDecoder.DecodeBasicBlock(Code, 0, ShaderType);
|
||||
ShaderIrBlock Block = ShaderDecoder.DecodeBasicBlock(Code, 0);
|
||||
|
||||
ShaderIrNode[] Nodes = Block.GetNodes();
|
||||
|
||||
|
|
|
@ -74,11 +74,9 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
for (int Ch = 0; Ch < 4; Ch++)
|
||||
{
|
||||
ShaderIrOperGpr Dst = (Ch >> 1) != 0
|
||||
? GetOperGpr28(OpCode)
|
||||
: GetOperGpr0 (OpCode);
|
||||
|
||||
Dst.Index += Ch & 1;
|
||||
//Assign it to a temp because the destination registers
|
||||
//may be used as texture coord input aswell.
|
||||
ShaderIrOperGpr Dst = new ShaderIrOperGpr(0x100 + Ch);
|
||||
|
||||
ShaderIrMetaTex Meta = new ShaderIrMetaTex(Ch);
|
||||
|
||||
|
@ -86,6 +84,19 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
Block.AddNode(GetPredNode(new ShaderIrAsg(Dst, Op), OpCode));
|
||||
}
|
||||
|
||||
for (int Ch = 0; Ch < 4; Ch++)
|
||||
{
|
||||
ShaderIrOperGpr Src = new ShaderIrOperGpr(0x100 + Ch);
|
||||
|
||||
ShaderIrOperGpr Dst = (Ch >> 1) != 0
|
||||
? GetOperGpr28(OpCode)
|
||||
: GetOperGpr0 (OpCode);
|
||||
|
||||
Dst.Index += Ch & 1;
|
||||
|
||||
Block.AddNode(GetPredNode(new ShaderIrAsg(Dst, Src), OpCode));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
{
|
||||
static class ShaderDecoder
|
||||
{
|
||||
public static ShaderIrBlock DecodeBasicBlock(int[] Code, int Offset, GalShaderType ShaderType)
|
||||
public static ShaderIrBlock DecodeBasicBlock(int[] Code, int Offset)
|
||||
{
|
||||
ShaderIrBlock Block = new ShaderIrBlock();
|
||||
|
||||
|
@ -37,8 +37,6 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
}
|
||||
}
|
||||
|
||||
Block.RunOptimizationPasses(ShaderType);
|
||||
|
||||
return Block;
|
||||
}
|
||||
|
||||
|
|
|
@ -16,11 +16,6 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
Nodes.Add(Node);
|
||||
}
|
||||
|
||||
public void RunOptimizationPasses(GalShaderType ShaderType)
|
||||
{
|
||||
ShaderOptExprProp.Optimize(Nodes, ShaderType);
|
||||
}
|
||||
|
||||
public ShaderIrNode[] GetNodes()
|
||||
{
|
||||
return Nodes.ToArray();
|
||||
|
|
|
@ -1,366 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Graphics.Gal.Shader
|
||||
{
|
||||
static class ShaderOptExprProp
|
||||
{
|
||||
private struct UseSite
|
||||
{
|
||||
public ShaderIrNode Parent { get; private set; }
|
||||
public ShaderIrCond Cond { get; private set; }
|
||||
|
||||
public int UseIndex { get; private set; }
|
||||
|
||||
public int OperIndex { get; private set; }
|
||||
|
||||
public UseSite(
|
||||
ShaderIrNode Parent,
|
||||
ShaderIrCond Cond,
|
||||
int UseIndex,
|
||||
int OperIndex)
|
||||
{
|
||||
this.Parent = Parent;
|
||||
this.Cond = Cond;
|
||||
this.UseIndex = UseIndex;
|
||||
this.OperIndex = OperIndex;
|
||||
}
|
||||
}
|
||||
|
||||
private class RegUse
|
||||
{
|
||||
public ShaderIrAsg Asg { get; private set; }
|
||||
|
||||
public int AsgIndex { get; private set; }
|
||||
|
||||
public int LastSiteIndex { get; private set; }
|
||||
|
||||
public ShaderIrCond Cond { get; private set; }
|
||||
|
||||
private List<UseSite> Sites;
|
||||
|
||||
public RegUse()
|
||||
{
|
||||
Sites = new List<UseSite>();
|
||||
}
|
||||
|
||||
public void AddUseSite(UseSite Site)
|
||||
{
|
||||
if (LastSiteIndex < Site.UseIndex)
|
||||
{
|
||||
LastSiteIndex = Site.UseIndex;
|
||||
}
|
||||
|
||||
Sites.Add(Site);
|
||||
}
|
||||
|
||||
public bool TryPropagate()
|
||||
{
|
||||
//This happens when a untiliazied register is used,
|
||||
//this usually indicates a decoding error, but may also
|
||||
//be caused by bogus programs (?). In any case, we just
|
||||
//keep the unitialized access and avoid trying to propagate
|
||||
//the expression (since we can't propagate what doesn't yet exist).
|
||||
if (Asg == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Cond != null)
|
||||
{
|
||||
//If the assignment is conditional, we can only propagate
|
||||
//to the use sites that shares the same condition of the assignment.
|
||||
foreach (UseSite Site in Sites)
|
||||
{
|
||||
if (!IsSameCondition(Cond, Site.Cond))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Sites.Count > 0)
|
||||
{
|
||||
foreach (UseSite Site in Sites)
|
||||
{
|
||||
if (Site.Parent is ShaderIrCond Cond)
|
||||
{
|
||||
switch (Site.OperIndex)
|
||||
{
|
||||
case 0: Cond.Pred = Asg.Src; break;
|
||||
case 1: Cond.Child = Asg.Src; break;
|
||||
|
||||
default: throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
else if (Site.Parent is ShaderIrOp Op)
|
||||
{
|
||||
switch (Site.OperIndex)
|
||||
{
|
||||
case 0: Op.OperandA = Asg.Src; break;
|
||||
case 1: Op.OperandB = Asg.Src; break;
|
||||
case 2: Op.OperandC = Asg.Src; break;
|
||||
|
||||
default: throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
else if (Site.Parent is ShaderIrAsg SiteAsg)
|
||||
{
|
||||
SiteAsg.Src = Asg.Src;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void SetNewAsg(ShaderIrAsg Asg, int AsgIndex, ShaderIrCond Cond)
|
||||
{
|
||||
this.Asg = Asg;
|
||||
this.AsgIndex = AsgIndex;
|
||||
this.Cond = Cond;
|
||||
|
||||
LastSiteIndex = 0;
|
||||
|
||||
Sites.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
public static void Optimize(List<ShaderIrNode> Nodes, GalShaderType ShaderType)
|
||||
{
|
||||
Dictionary<int, RegUse> Uses = new Dictionary<int, RegUse>();
|
||||
|
||||
RegUse GetUse(int Key)
|
||||
{
|
||||
RegUse Use;
|
||||
|
||||
if (!Uses.TryGetValue(Key, out Use))
|
||||
{
|
||||
Use = new RegUse();
|
||||
|
||||
Uses.Add(Key, Use);
|
||||
}
|
||||
|
||||
return Use;
|
||||
}
|
||||
|
||||
int GetGprKey(int GprIndex)
|
||||
{
|
||||
return GprIndex;
|
||||
}
|
||||
|
||||
int GetPredKey(int PredIndex)
|
||||
{
|
||||
return PredIndex | 0x10000000;
|
||||
}
|
||||
|
||||
RegUse GetGprUse(int GprIndex)
|
||||
{
|
||||
return GetUse(GetGprKey(GprIndex));
|
||||
}
|
||||
|
||||
RegUse GetPredUse(int PredIndex)
|
||||
{
|
||||
return GetUse(GetPredKey(PredIndex));
|
||||
}
|
||||
|
||||
void RemoveUse(RegUse Use)
|
||||
{
|
||||
if (!Nodes.Remove((ShaderIrNode)Use.Cond ?? Use.Asg))
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
void FindRegUses(
|
||||
List<(int, UseSite)> UseList,
|
||||
ShaderIrNode Parent,
|
||||
ShaderIrNode Node,
|
||||
ShaderIrCond CondNode,
|
||||
int UseIndex,
|
||||
int OperIndex = 0)
|
||||
{
|
||||
if (Node is ShaderIrAsg Asg)
|
||||
{
|
||||
FindRegUses(UseList, Asg, Asg.Src, CondNode, UseIndex);
|
||||
}
|
||||
else if (Node is ShaderIrCond Cond)
|
||||
{
|
||||
FindRegUses(UseList, Cond, Cond.Pred, CondNode, UseIndex, 0);
|
||||
FindRegUses(UseList, Cond, Cond.Child, CondNode, UseIndex, 1);
|
||||
}
|
||||
else if (Node is ShaderIrOp Op)
|
||||
{
|
||||
FindRegUses(UseList, Op, Op.OperandA, CondNode, UseIndex, 0);
|
||||
FindRegUses(UseList, Op, Op.OperandB, CondNode, UseIndex, 1);
|
||||
FindRegUses(UseList, Op, Op.OperandC, CondNode, UseIndex, 2);
|
||||
}
|
||||
else if (Node is ShaderIrOperGpr Gpr && !Gpr.IsConst)
|
||||
{
|
||||
UseList.Add((GetGprKey(Gpr.Index), new UseSite(Parent, CondNode, UseIndex, OperIndex)));
|
||||
}
|
||||
else if (Node is ShaderIrOperPred Pred)
|
||||
{
|
||||
UseList.Add((GetPredKey(Pred.Index), new UseSite(Parent, CondNode, UseIndex, OperIndex)));
|
||||
}
|
||||
}
|
||||
|
||||
void TryAddRegUseSite(ShaderIrNode Node, ShaderIrCond CondNode, int UseIndex)
|
||||
{
|
||||
List<(int, UseSite)> UseList = new List<(int, UseSite)>();
|
||||
|
||||
FindRegUses(UseList, null, Node, CondNode, UseIndex);
|
||||
|
||||
foreach ((int Key, UseSite Site) in UseList)
|
||||
{
|
||||
GetUse(Key).AddUseSite(Site);
|
||||
}
|
||||
}
|
||||
|
||||
bool TryPropagate(RegUse Use)
|
||||
{
|
||||
//We can only propagate if the registers that the expression depends
|
||||
//on weren't assigned after the original expression assignment
|
||||
//to a register took place. We traverse the expression tree to find
|
||||
//all registers being used, if any of those registers was assigned
|
||||
//after the assignment to be propagated, then we can't propagate.
|
||||
if (Use?.Asg == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
List<(int, UseSite)> UseList = new List<(int, UseSite)>();
|
||||
|
||||
if (Use.Cond != null)
|
||||
{
|
||||
FindRegUses(UseList, null, Use.Cond, null, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
FindRegUses(UseList, Use.Asg, Use.Asg.Src, null, 0);
|
||||
}
|
||||
|
||||
foreach ((int Key, UseSite Site) in UseList)
|
||||
{
|
||||
//TODO: Build an assignment list inside RegUse,
|
||||
//and check if there is an assignment inside the
|
||||
//range of Use.AsgIndex and Use.LastSiteIndex,
|
||||
//and if that's the case, then we should return false.
|
||||
//The current method is too conservative.
|
||||
if (GetUse(Key).AsgIndex >= Use.AsgIndex)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return Use.TryPropagate();
|
||||
}
|
||||
|
||||
for (int Index = 0, IterCount = 0; Index < Nodes.Count; Index++, IterCount++)
|
||||
{
|
||||
ShaderIrNode Node = Nodes[Index];
|
||||
|
||||
ShaderIrCond CondNode = null;
|
||||
|
||||
if (Node is ShaderIrCond)
|
||||
{
|
||||
CondNode = (ShaderIrCond)Node;
|
||||
}
|
||||
|
||||
TryAddRegUseSite(Node, CondNode, IterCount);;
|
||||
|
||||
while (Node is ShaderIrCond Cond)
|
||||
{
|
||||
Node = Cond.Child;
|
||||
}
|
||||
|
||||
if (!(Node is ShaderIrAsg Asg))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
RegUse Use = null;
|
||||
|
||||
if (Asg.Dst is ShaderIrOperGpr Gpr && !Gpr.IsConst)
|
||||
{
|
||||
Use = GetGprUse(Gpr.Index);
|
||||
}
|
||||
else if (Asg.Dst is ShaderIrOperPred Pred)
|
||||
{
|
||||
Use = GetPredUse(Pred.Index);
|
||||
}
|
||||
|
||||
bool CanRemoveAsg = CondNode == null;
|
||||
|
||||
CanRemoveAsg |= IsSameCondition(CondNode, Use?.Cond);
|
||||
|
||||
if (CanRemoveAsg && TryPropagate(Use))
|
||||
{
|
||||
RemoveUse(Use);
|
||||
|
||||
//Note: Only decrement if the removal was successful.
|
||||
//RemoveUse throws when this is not the case so we should be good.
|
||||
Index--;
|
||||
}
|
||||
|
||||
//All nodes inside conditional nodes can't be propagated,
|
||||
//as we don't even know if they will be executed to begin with.
|
||||
Use?.SetNewAsg(Asg, IterCount, CondNode);
|
||||
}
|
||||
|
||||
foreach (RegUse Use in Uses.Values)
|
||||
{
|
||||
//Gprs 0-3 are the color output on fragment shaders,
|
||||
//so we can't remove the last assignments to those registers.
|
||||
if (ShaderType == GalShaderType.Fragment)
|
||||
{
|
||||
if (Use.Asg?.Dst is ShaderIrOperGpr Gpr && Gpr.Index < 4)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (TryPropagate(Use))
|
||||
{
|
||||
RemoveUse(Use);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsSameCondition(ShaderIrCond CondA, ShaderIrCond CondB)
|
||||
{
|
||||
if (CondA == null || CondB == null)
|
||||
{
|
||||
return CondA == CondB;
|
||||
}
|
||||
|
||||
if (CondA.Not != CondB.Not)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (CondA.Pred is ShaderIrOperPred PredA)
|
||||
{
|
||||
if (!(CondB.Pred is ShaderIrOperPred PredB))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (PredA.Index != PredB.Index)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (CondA.Pred != CondB.Pred)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,9 +9,9 @@ namespace Ryujinx.Graphics.Gpu
|
|||
|
||||
internal NsGpuMemoryMgr MemoryMgr { get; private set; }
|
||||
|
||||
public NvGpuFifo Fifo;
|
||||
public NvGpuFifo Fifo { get; private set; }
|
||||
|
||||
internal NvGpuEngine3d Engine3d;
|
||||
public NvGpuEngine3d Engine3d { get; private set; }
|
||||
|
||||
private Thread FifoProcessing;
|
||||
|
||||
|
@ -29,7 +29,7 @@ namespace Ryujinx.Graphics.Gpu
|
|||
|
||||
KeepRunning = true;
|
||||
|
||||
FifoProcessing = new Thread(ProcessFifo);
|
||||
FifoProcessing = new Thread(ProcessFifo);
|
||||
|
||||
FifoProcessing.Start();
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ using System.Collections.Generic;
|
|||
|
||||
namespace Ryujinx.Graphics.Gpu
|
||||
{
|
||||
class NvGpuEngine3d : INvGpuEngine
|
||||
public class NvGpuEngine3d : INvGpuEngine
|
||||
{
|
||||
public int[] Registers { get; private set; }
|
||||
|
||||
|
@ -249,6 +249,8 @@ namespace Ryujinx.Graphics.Gpu
|
|||
TicPosition += TicIndex * 0x20;
|
||||
TscPosition += TscIndex * 0x20;
|
||||
|
||||
GalTextureSampler Sampler = TextureFactory.MakeSampler(Gpu, Memory, TscPosition);
|
||||
|
||||
long TextureAddress = Memory.ReadInt64(TicPosition + 4) & 0xffffffffffff;
|
||||
|
||||
if (FrameBuffers.Contains(TextureAddress))
|
||||
|
@ -257,15 +259,15 @@ namespace Ryujinx.Graphics.Gpu
|
|||
//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.BindFrameBufferTexture(TextureAddress, TexIndex);
|
||||
Gpu.Renderer.BindFrameBufferTexture(TextureAddress, TexIndex, Sampler);
|
||||
}
|
||||
else
|
||||
{
|
||||
Gpu.Renderer.SetTexture(TexIndex, TextureFactory.MakeTexture(Gpu, Memory, TicPosition));
|
||||
GalTexture Texture = TextureFactory.MakeTexture(Gpu, Memory, TicPosition);
|
||||
|
||||
Gpu.Renderer.SetTextureAndSampler(TexIndex, Texture, Sampler);
|
||||
Gpu.Renderer.BindTexture(TexIndex);
|
||||
}
|
||||
|
||||
Gpu.Renderer.SetSampler(TextureFactory.MakeSampler(Gpu, Memory, TscPosition));
|
||||
}
|
||||
|
||||
private void UploadUniforms(AMemory Memory)
|
||||
|
@ -488,5 +490,10 @@ namespace Ryujinx.Graphics.Gpu
|
|||
{
|
||||
Registers[(int)Reg] = Value;
|
||||
}
|
||||
|
||||
public bool IsFrameBufferPosition(long Position)
|
||||
{
|
||||
return FrameBuffers.Contains(Position);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@ using Ryujinx.Graphics.Gal;
|
|||
|
||||
namespace Ryujinx.Graphics.Gpu
|
||||
{
|
||||
struct Texture
|
||||
public struct Texture
|
||||
{
|
||||
public long Position { get; private set; }
|
||||
|
||||
|
@ -16,6 +16,24 @@ namespace Ryujinx.Graphics.Gpu
|
|||
|
||||
public GalTextureFormat Format { get; private set; }
|
||||
|
||||
public Texture(
|
||||
long Position,
|
||||
int Width,
|
||||
int Height)
|
||||
{
|
||||
this.Position = Position;
|
||||
this.Width = Width;
|
||||
this.Height = Height;
|
||||
|
||||
Pitch = 0;
|
||||
|
||||
BlockHeight = 16;
|
||||
|
||||
Swizzle = TextureSwizzle.BlockLinear;
|
||||
|
||||
Format = GalTextureFormat.A8B8G8R8;
|
||||
}
|
||||
|
||||
public Texture(
|
||||
long Position,
|
||||
int Width,
|
||||
|
|
|
@ -4,7 +4,7 @@ using System;
|
|||
|
||||
namespace Ryujinx.Graphics.Gpu
|
||||
{
|
||||
static class TextureReader
|
||||
public static class TextureReader
|
||||
{
|
||||
public static byte[] Read(AMemory Memory, Texture Texture)
|
||||
{
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
namespace Ryujinx.Graphics.Gpu
|
||||
{
|
||||
enum TextureSwizzle
|
||||
public enum TextureSwizzle
|
||||
{
|
||||
_1dBuffer = 0,
|
||||
PitchColorKey = 1,
|
||||
|
|
|
@ -38,8 +38,6 @@ namespace Ryujinx
|
|||
protected override void OnLoad(EventArgs e)
|
||||
{
|
||||
VSync = VSyncMode.On;
|
||||
|
||||
Renderer.InitializeFrameBuffer();
|
||||
}
|
||||
|
||||
protected override void OnUpdateFrame(FrameEventArgs e)
|
||||
|
|
Loading…
Add table
Reference in a new issue