Somewhat better NvFlinger (I guess) (fixes #30)

This commit is contained in:
gdkchan 2018-02-23 18:48:27 -03:00
parent eafc58c9f2
commit 2ed733b1d5
14 changed files with 820 additions and 444 deletions

View file

@ -0,0 +1,20 @@
using System.IO;
using System.Reflection;
namespace Ryujinx.Graphics.Gal
{
static class EmbeddedResource
{
public static string GetString(string Name)
{
Assembly Asm = typeof(EmbeddedResource).Assembly;
using (Stream ResStream = Asm.GetManifestResourceStream(Name))
{
StreamReader Reader = new StreamReader(ResStream);
return Reader.ReadToEnd();
}
}
}
}

View file

@ -2,14 +2,15 @@ using System;
namespace Ryujinx.Graphics.Gal
{
public interface IGalRenderer
public unsafe interface IGalRenderer
{
long FrameBufferPtr { get; set; }
void QueueAction(Action ActionMthd);
void RunActions();
void InitializeFrameBuffer();
void Render();
void SetWindowSize(int Width, int Height);
void SetFrameBuffer(byte* Fb, int Width, int Height, float SX, float SY, float R);
void SendVertexBuffer(int Index, byte[] Buffer, int Stride, GalVertexAttrib[] Attribs);
void SendR8G8B8A8Texture(int Index, byte[] Buffer, int Width, int Height);
void BindTexture(int Index);

View file

@ -0,0 +1,13 @@
#version 330 core
precision highp float;
uniform sampler2D tex;
in vec2 tex_coord;
out vec4 out_frag_color;
void main(void) {
out_frag_color = texture(tex, tex_coord);
}

View file

@ -0,0 +1,26 @@
#version 330 core
precision highp float;
uniform vec2 window_size;
uniform mat2 transform;
layout(location = 0) in vec2 in_position;
layout(location = 1) in vec2 in_tex_coord;
out vec2 tex_coord;
// Have a fixed aspect ratio, fit the image within the available space.
vec2 get_scale_ratio(void) {
vec2 native_size = vec2(1280, 720);
vec2 ratio = vec2(
(window_size.y * native_size.x) / (native_size.y * window_size.x),
(window_size.x * native_size.y) / (native_size.x * window_size.y)
);
return min(ratio, 1);
}
void main(void) {
tex_coord = in_tex_coord;
gl_Position = vec4((transform * in_position) * get_scale_ratio(), 0, 1);
}

View file

@ -0,0 +1,228 @@
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;
public FrameBuffer(int Width, int Height)
{
if (Width < 0)
{
throw new ArgumentOutOfRangeException(nameof(Width));
}
if (Height < 0)
{
throw new ArgumentOutOfRangeException(nameof(Height));
}
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)
{
if (Fb == null)
{
throw new ArgumentNullException(nameof(Fb));
}
if (Width < 0)
{
throw new ArgumentOutOfRangeException(nameof(Width));
}
if (Height < 0)
{
throw new ArgumentOutOfRangeException(nameof(Height));
}
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));
}
public void Render()
{
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;
}
}
}

View file

@ -1,7 +1,9 @@
using OpenTK;
using OpenTK.Graphics.OpenGL;
using System;
using System.Collections.Generic;
namespace Ryujinx.Graphics.Gal.OpenGL
{
public class OpenGLRenderer : IGalRenderer
@ -25,6 +27,8 @@ namespace Ryujinx.Graphics.Gal.OpenGL
private Queue<Action> ActionsQueue;
private FrameBuffer FbRenderer;
public long FrameBufferPtr { get; set; }
public OpenGLRenderer()
@ -36,6 +40,11 @@ namespace Ryujinx.Graphics.Gal.OpenGL
ActionsQueue = new Queue<Action>();
}
public void InitializeFrameBuffer()
{
FbRenderer = new FrameBuffer(1280, 720);
}
public void QueueAction(Action ActionMthd)
{
ActionsQueue.Enqueue(ActionMthd);
@ -43,14 +52,18 @@ namespace Ryujinx.Graphics.Gal.OpenGL
public void RunActions()
{
while (ActionsQueue.Count > 0)
int Count = ActionsQueue.Count;
while (Count-- > 0)
{
ActionsQueue.Dequeue()();
}
}
}
public void Render()
{
FbRenderer.Render();
for (int Index = 0; Index < VertexBuffers.Count; Index++)
{
VertexBuffer Vb = VertexBuffers[Index];
@ -62,7 +75,28 @@ namespace Ryujinx.Graphics.Gal.OpenGL
GL.DrawArrays(PrimitiveType.TriangleStrip, 0, Vb.PrimCount);
}
}
}
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 Rotate)
{
Matrix2 Transform;
Transform = Matrix2.CreateScale(ScaleX, ScaleY);
Transform *= Matrix2.CreateRotation(Rotate);
FbRenderer.Set(Fb, Width, Height, Transform);
}
public void SendVertexBuffer(int Index, byte[] Buffer, int Stride, GalVertexAttrib[] Attribs)

View file

@ -4,6 +4,14 @@
<TargetFramework>netcoreapp2.0</TargetFramework>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="OpenTK.NETCore" Version="1.1.2749.6433" />
</ItemGroup>
@ -12,4 +20,13 @@
<ProjectReference Include="..\ChocolArm64\ChocolArm64.csproj" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Gal\OpenGL\FbVtxShader.glsl">
<LogicalName>GlFbVtxShader</LogicalName>
</EmbeddedResource>
<EmbeddedResource Include="Gal\OpenGL\FbFragShader.glsl">
<LogicalName>GlFbFragShader</LogicalName>
</EmbeddedResource>
</ItemGroup>
</Project>