Blit framebuffer without shaders (#229)
* Blit framebuffer without shaders * De-hardcode native size values * Adapt to dehardcoded framebuffers and address feedback * Remove framebuffer rebinding
This commit is contained in:
parent
ed29982f9b
commit
1344a47c77
6 changed files with 101 additions and 288 deletions
|
@ -14,7 +14,7 @@ namespace Ryujinx.Graphics.Gal
|
||||||
|
|
||||||
void Set(byte[] Data, int Width, int Height);
|
void Set(byte[] Data, int Width, int Height);
|
||||||
|
|
||||||
void SetTransform(float SX, float SY, float Rotate, float TX, float TY);
|
void SetTransform(bool FlipX, bool FlipY, int Top, int Left, int Right, int Bottom);
|
||||||
|
|
||||||
void SetWindowSize(int Width, int Height);
|
void SetWindowSize(int Width, int Height);
|
||||||
|
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
#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);
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
#version 330 core
|
|
||||||
|
|
||||||
precision highp float;
|
|
||||||
|
|
||||||
uniform mat2 transform;
|
|
||||||
uniform vec2 window_size;
|
|
||||||
uniform vec2 offset;
|
|
||||||
|
|
||||||
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;
|
|
||||||
vec2 t_pos = (transform * in_position) + offset;
|
|
||||||
gl_Position = vec4(t_pos * get_scale_ratio(), 0, 1);
|
|
||||||
}
|
|
|
@ -32,48 +32,45 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
public int RbHandle { get; private set; }
|
public int RbHandle { get; private set; }
|
||||||
public int TexHandle { get; private set; }
|
public int TexHandle { get; private set; }
|
||||||
|
|
||||||
public FrameBuffer(int Width, int Height)
|
public FrameBuffer(int Width, int Height, bool HasRenderBuffer)
|
||||||
{
|
{
|
||||||
this.Width = Width;
|
this.Width = Width;
|
||||||
this.Height = Height;
|
this.Height = Height;
|
||||||
|
|
||||||
Handle = GL.GenFramebuffer();
|
Handle = GL.GenFramebuffer();
|
||||||
RbHandle = GL.GenRenderbuffer();
|
|
||||||
TexHandle = GL.GenTexture();
|
TexHandle = GL.GenTexture();
|
||||||
|
|
||||||
|
if (HasRenderBuffer)
|
||||||
|
{
|
||||||
|
RbHandle = GL.GenRenderbuffer();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct ShaderProgram
|
private const int NativeWidth = 1280;
|
||||||
{
|
private const int NativeHeight = 720;
|
||||||
public int Handle;
|
|
||||||
public int VpHandle;
|
|
||||||
public int FpHandle;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Dictionary<long, FrameBuffer> Fbs;
|
private Dictionary<long, FrameBuffer> Fbs;
|
||||||
|
|
||||||
private ShaderProgram Shader;
|
|
||||||
|
|
||||||
private Rect Viewport;
|
private Rect Viewport;
|
||||||
private Rect Window;
|
private Rect Window;
|
||||||
|
|
||||||
private bool IsInitialized;
|
private FrameBuffer CurrFb;
|
||||||
|
private FrameBuffer CurrReadFb;
|
||||||
|
|
||||||
private int RawFbTexWidth;
|
private FrameBuffer RawFb;
|
||||||
private int RawFbTexHeight;
|
|
||||||
private int RawFbTexHandle;
|
|
||||||
|
|
||||||
private int CurrFbHandle;
|
private bool FlipX;
|
||||||
private int CurrTexHandle;
|
private bool FlipY;
|
||||||
|
|
||||||
private int VaoHandle;
|
private int CropTop;
|
||||||
private int VboHandle;
|
private int CropLeft;
|
||||||
|
private int CropRight;
|
||||||
|
private int CropBottom;
|
||||||
|
|
||||||
public OGLFrameBuffer()
|
public OGLFrameBuffer()
|
||||||
{
|
{
|
||||||
Fbs = new Dictionary<long, FrameBuffer>();
|
Fbs = new Dictionary<long, FrameBuffer>();
|
||||||
|
|
||||||
Shader = new ShaderProgram();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Create(long Key, int Width, int Height)
|
public void Create(long Key, int Width, int Height)
|
||||||
|
@ -92,7 +89,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Fb = new FrameBuffer(Width, Height);
|
Fb = new FrameBuffer(Width, Height, true);
|
||||||
|
|
||||||
SetupTexture(Fb.TexHandle, Width, Height);
|
SetupTexture(Fb.TexHandle, Width, Height);
|
||||||
|
|
||||||
|
@ -129,7 +126,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
{
|
{
|
||||||
GL.BindFramebuffer(FramebufferTarget.Framebuffer, Fb.Handle);
|
GL.BindFramebuffer(FramebufferTarget.Framebuffer, Fb.Handle);
|
||||||
|
|
||||||
CurrFbHandle = Fb.Handle;
|
CurrFb = Fb;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,75 +144,50 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
{
|
{
|
||||||
if (Fbs.TryGetValue(Key, out FrameBuffer Fb))
|
if (Fbs.TryGetValue(Key, out FrameBuffer Fb))
|
||||||
{
|
{
|
||||||
CurrTexHandle = Fb.TexHandle;
|
CurrReadFb = Fb;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Set(byte[] Data, int Width, int Height)
|
public void Set(byte[] Data, int Width, int Height)
|
||||||
{
|
{
|
||||||
if (RawFbTexHandle == 0)
|
if (RawFb == null)
|
||||||
{
|
{
|
||||||
RawFbTexHandle = GL.GenTexture();
|
CreateRawFb(Width, Height);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (RawFbTexWidth != Width ||
|
if (RawFb.Width != Width ||
|
||||||
RawFbTexHeight != Height)
|
RawFb.Height != Height)
|
||||||
{
|
{
|
||||||
SetupTexture(RawFbTexHandle, Width, Height);
|
SetupTexture(RawFb.TexHandle, Width, Height);
|
||||||
|
|
||||||
RawFbTexWidth = Width;
|
RawFb.Width = Width;
|
||||||
RawFbTexHeight = Height;
|
RawFb.Height = Height;
|
||||||
}
|
}
|
||||||
|
|
||||||
GL.ActiveTexture(TextureUnit.Texture0);
|
GL.ActiveTexture(TextureUnit.Texture0);
|
||||||
|
|
||||||
GL.BindTexture(TextureTarget.Texture2D, RawFbTexHandle);
|
GL.BindTexture(TextureTarget.Texture2D, RawFb.TexHandle);
|
||||||
|
|
||||||
(PixelFormat Format, PixelType Type) = OGLEnumConverter.GetTextureFormat(GalTextureFormat.A8B8G8R8);
|
(PixelFormat Format, PixelType Type) = OGLEnumConverter.GetTextureFormat(GalTextureFormat.A8B8G8R8);
|
||||||
|
|
||||||
GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, 0, Width, Height, Format, Type, Data);
|
GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, 0, Width, Height, Format, Type, Data);
|
||||||
|
|
||||||
CurrTexHandle = RawFbTexHandle;
|
CurrReadFb = RawFb;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetTransform(float SX, float SY, float Rotate, float TX, float TY)
|
public void SetTransform(bool FlipX, bool FlipY, int Top, int Left, int Right, int Bottom)
|
||||||
{
|
{
|
||||||
EnsureInitialized();
|
this.FlipX = FlipX;
|
||||||
|
this.FlipY = FlipY;
|
||||||
|
|
||||||
Matrix2 Transform;
|
CropTop = Top;
|
||||||
|
CropLeft = Left;
|
||||||
Transform = Matrix2.CreateScale(SX, SY);
|
CropRight = Right;
|
||||||
Transform *= Matrix2.CreateRotation(Rotate);
|
CropBottom = Bottom;
|
||||||
|
|
||||||
Vector2 Offs = new Vector2(TX, TY);
|
|
||||||
|
|
||||||
int CurrentProgram = GL.GetInteger(GetPName.CurrentProgram);
|
|
||||||
|
|
||||||
GL.UseProgram(Shader.Handle);
|
|
||||||
|
|
||||||
int TransformUniformLocation = GL.GetUniformLocation(Shader.Handle, "transform");
|
|
||||||
|
|
||||||
GL.UniformMatrix2(TransformUniformLocation, false, ref Transform);
|
|
||||||
|
|
||||||
int OffsetUniformLocation = GL.GetUniformLocation(Shader.Handle, "offset");
|
|
||||||
|
|
||||||
GL.Uniform2(OffsetUniformLocation, ref Offs);
|
|
||||||
|
|
||||||
GL.UseProgram(CurrentProgram);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetWindowSize(int Width, int Height)
|
public void SetWindowSize(int Width, int Height)
|
||||||
{
|
{
|
||||||
int CurrentProgram = GL.GetInteger(GetPName.CurrentProgram);
|
|
||||||
|
|
||||||
GL.UseProgram(Shader.Handle);
|
|
||||||
|
|
||||||
int WindowSizeUniformLocation = GL.GetUniformLocation(Shader.Handle, "window_size");
|
|
||||||
|
|
||||||
GL.Uniform2(WindowSizeUniformLocation, new Vector2(Width, Height));
|
|
||||||
|
|
||||||
GL.UseProgram(CurrentProgram);
|
|
||||||
|
|
||||||
Window = new Rect(0, 0, Width, Height);
|
Window = new Rect(0, 0, Width, Height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -237,72 +209,59 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
|
||||||
public void Render()
|
public void Render()
|
||||||
{
|
{
|
||||||
if (CurrTexHandle != 0)
|
if (CurrReadFb != null)
|
||||||
{
|
{
|
||||||
EnsureInitialized();
|
int SrcX0, SrcX1, SrcY0, SrcY1;
|
||||||
|
|
||||||
//bool CullFaceEnable = GL.IsEnabled(EnableCap.CullFace);
|
if (CropLeft == 0 && CropRight == 0)
|
||||||
|
{
|
||||||
|
SrcX0 = 0;
|
||||||
|
SrcX1 = CurrReadFb.Width;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SrcX0 = CropLeft;
|
||||||
|
SrcX1 = CropRight;
|
||||||
|
}
|
||||||
|
|
||||||
bool DepthTestEnable = GL.IsEnabled(EnableCap.DepthTest);
|
if (CropTop == 0 && CropBottom == 0)
|
||||||
|
{
|
||||||
|
SrcY0 = 0;
|
||||||
|
SrcY1 = CurrReadFb.Height;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SrcY0 = CropTop;
|
||||||
|
SrcY1 = CropBottom;
|
||||||
|
}
|
||||||
|
|
||||||
bool StencilTestEnable = GL.IsEnabled(EnableCap.StencilTest);
|
float RatioX = MathF.Min(1f, (Window.Height * (float)NativeWidth) / ((float)NativeHeight * Window.Width));
|
||||||
|
float RatioY = MathF.Min(1f, (Window.Width * (float)NativeHeight) / ((float)NativeWidth * Window.Height));
|
||||||
|
|
||||||
bool AlphaBlendEnable = GL.IsEnabled(EnableCap.Blend);
|
int DstWidth = (int)(Window.Width * RatioX);
|
||||||
|
int DstHeight = (int)(Window.Height * RatioY);
|
||||||
|
|
||||||
//GL.Disable(EnableCap.CullFace);
|
int DstPaddingX = (Window.Width - DstWidth) / 2;
|
||||||
|
int DstPaddingY = (Window.Height - DstHeight) / 2;
|
||||||
|
|
||||||
GL.Disable(EnableCap.DepthTest);
|
int DstX0 = FlipX ? Window.Width - DstPaddingX : DstPaddingX;
|
||||||
|
int DstX1 = FlipX ? DstPaddingX : Window.Width - DstPaddingX;
|
||||||
|
|
||||||
GL.Disable(EnableCap.StencilTest);
|
int DstY0 = FlipY ? DstPaddingY : Window.Height - DstPaddingY;
|
||||||
|
int DstY1 = FlipY ? Window.Height - DstPaddingY : DstPaddingY;
|
||||||
GL.Disable(EnableCap.Blend);
|
|
||||||
|
|
||||||
GL.ActiveTexture(TextureUnit.Texture0);
|
|
||||||
|
|
||||||
GL.BindTexture(TextureTarget.Texture2D, CurrTexHandle);
|
|
||||||
|
|
||||||
int CurrentProgram = GL.GetInteger(GetPName.CurrentProgram);
|
|
||||||
|
|
||||||
GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
|
GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
|
||||||
|
|
||||||
SetViewport(Window);
|
GL.Viewport(0, 0, Window.Width, Window.Height);
|
||||||
|
|
||||||
GL.Clear(
|
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, CurrReadFb.Handle);
|
||||||
ClearBufferMask.ColorBufferBit |
|
|
||||||
ClearBufferMask.DepthBufferBit);
|
|
||||||
|
|
||||||
GL.BindVertexArray(VaoHandle);
|
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
|
||||||
|
|
||||||
GL.UseProgram(Shader.Handle);
|
GL.BlitFramebuffer(
|
||||||
|
SrcX0, SrcY0, SrcX1, SrcY1,
|
||||||
GL.DrawArrays(PrimitiveType.TriangleStrip, 0, 4);
|
DstX0, DstY0, DstX1, DstY1,
|
||||||
|
ClearBufferMask.ColorBufferBit, BlitFramebufferFilter.Linear);
|
||||||
//Restore the original state.
|
|
||||||
GL.BindFramebuffer(FramebufferTarget.Framebuffer, CurrFbHandle);
|
|
||||||
|
|
||||||
GL.UseProgram(CurrentProgram);
|
|
||||||
|
|
||||||
//if (CullFaceEnable)
|
|
||||||
//{
|
|
||||||
// GL.Enable(EnableCap.CullFace);
|
|
||||||
//}
|
|
||||||
|
|
||||||
if (DepthTestEnable)
|
|
||||||
{
|
|
||||||
GL.Enable(EnableCap.DepthTest);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (StencilTestEnable)
|
|
||||||
{
|
|
||||||
GL.Enable(EnableCap.StencilTest);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (AlphaBlendEnable)
|
|
||||||
{
|
|
||||||
GL.Enable(EnableCap.Blend);
|
|
||||||
}
|
|
||||||
|
|
||||||
SetViewport(Viewport);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -354,8 +313,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
Data);
|
Data);
|
||||||
|
|
||||||
Callback(Data);
|
Callback(Data);
|
||||||
|
|
||||||
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, CurrFbHandle);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -390,86 +347,29 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EnsureInitialized()
|
private void CreateRawFb(int Width, int Height)
|
||||||
{
|
{
|
||||||
if (!IsInitialized)
|
if (RawFb == null)
|
||||||
{
|
{
|
||||||
IsInitialized = true;
|
RawFb = new FrameBuffer(Width, Height, false);
|
||||||
|
|
||||||
SetupShader();
|
SetupTexture(RawFb.TexHandle, Width, Height);
|
||||||
SetupVertex();
|
|
||||||
|
RawFb.Width = Width;
|
||||||
|
RawFb.Height = Height;
|
||||||
|
|
||||||
|
GL.BindFramebuffer(FramebufferTarget.Framebuffer, RawFb.Handle);
|
||||||
|
|
||||||
|
GL.FramebufferTexture(
|
||||||
|
FramebufferTarget.Framebuffer,
|
||||||
|
FramebufferAttachment.ColorAttachment0,
|
||||||
|
RawFb.TexHandle,
|
||||||
|
0);
|
||||||
|
|
||||||
|
GL.Viewport(0, 0, Width, Height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetupShader()
|
|
||||||
{
|
|
||||||
Shader.VpHandle = GL.CreateShader(ShaderType.VertexShader);
|
|
||||||
Shader.FpHandle = GL.CreateShader(ShaderType.FragmentShader);
|
|
||||||
|
|
||||||
string VpSource = EmbeddedResource.GetString("GlFbVtxShader");
|
|
||||||
string FpSource = EmbeddedResource.GetString("GlFbFragShader");
|
|
||||||
|
|
||||||
GL.ShaderSource(Shader.VpHandle, VpSource);
|
|
||||||
GL.ShaderSource(Shader.FpHandle, FpSource);
|
|
||||||
GL.CompileShader(Shader.VpHandle);
|
|
||||||
GL.CompileShader(Shader.FpHandle);
|
|
||||||
|
|
||||||
Shader.Handle = GL.CreateProgram();
|
|
||||||
|
|
||||||
GL.AttachShader(Shader.Handle, Shader.VpHandle);
|
|
||||||
GL.AttachShader(Shader.Handle, Shader.FpHandle);
|
|
||||||
GL.LinkProgram(Shader.Handle);
|
|
||||||
GL.UseProgram(Shader.Handle);
|
|
||||||
|
|
||||||
Matrix2 Transform = Matrix2.Identity;
|
|
||||||
|
|
||||||
int TexUniformLocation = GL.GetUniformLocation(Shader.Handle, "tex");
|
|
||||||
|
|
||||||
GL.Uniform1(TexUniformLocation, 0);
|
|
||||||
|
|
||||||
int WindowSizeUniformLocation = GL.GetUniformLocation(Shader.Handle, "window_size");
|
|
||||||
|
|
||||||
GL.Uniform2(WindowSizeUniformLocation, new Vector2(1280.0f, 720.0f));
|
|
||||||
|
|
||||||
int TransformUniformLocation = GL.GetUniformLocation(Shader.Handle, "transform");
|
|
||||||
|
|
||||||
GL.UniformMatrix2(TransformUniformLocation, false, ref Transform);
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SetupTexture(int Handle, int Width, int Height)
|
private void SetupTexture(int Handle, int Width, int Height)
|
||||||
{
|
{
|
||||||
GL.BindTexture(TextureTarget.Texture2D, Handle);
|
GL.BindTexture(TextureTarget.Texture2D, Handle);
|
||||||
|
|
|
@ -21,13 +21,4 @@
|
||||||
<ProjectReference Include="..\ChocolArm64\ChocolArm64.csproj" />
|
<ProjectReference Include="..\ChocolArm64\ChocolArm64.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<EmbeddedResource Include="Gal\OpenGL\FbVtxShader.glsl">
|
|
||||||
<LogicalName>GlFbVtxShader</LogicalName>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Include="Gal\OpenGL\FbFragShader.glsl">
|
|
||||||
<LogicalName>GlFbFragShader</LogicalName>
|
|
||||||
</EmbeddedResource>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
@ -293,54 +293,17 @@ namespace Ryujinx.HLE.OsHle.Services.Android
|
||||||
|
|
||||||
Rect Crop = BufferQueue[Slot].Crop;
|
Rect Crop = BufferQueue[Slot].Crop;
|
||||||
|
|
||||||
int RealWidth = FbWidth;
|
bool FlipX = BufferQueue[Slot].Transform.HasFlag(HalTransform.FlipX);
|
||||||
int RealHeight = FbHeight;
|
bool FlipY = BufferQueue[Slot].Transform.HasFlag(HalTransform.FlipY);
|
||||||
|
|
||||||
float XSign = BufferQueue[Slot].Transform.HasFlag(HalTransform.FlipX) ? -1 : 1;
|
//Rotation is being ignored
|
||||||
float YSign = BufferQueue[Slot].Transform.HasFlag(HalTransform.FlipY) ? -1 : 1;
|
|
||||||
|
|
||||||
float ScaleX = 1;
|
int Top = Crop.Top;
|
||||||
float ScaleY = 1;
|
int Left = Crop.Left;
|
||||||
|
int Right = Crop.Right;
|
||||||
|
int Bottom = Crop.Bottom;
|
||||||
|
|
||||||
float OffsX = 0;
|
Renderer.QueueAction(() => Renderer.FrameBuffer.SetTransform(FlipX, FlipY, Top, Left, Right, Bottom));
|
||||||
float OffsY = 0;
|
|
||||||
|
|
||||||
if (Crop.Right != 0 &&
|
|
||||||
Crop.Bottom != 0)
|
|
||||||
{
|
|
||||||
//Who knows if this is right, I was never good with math...
|
|
||||||
RealWidth = Crop.Right - Crop.Left;
|
|
||||||
RealHeight = Crop.Bottom - Crop.Top;
|
|
||||||
|
|
||||||
if (BufferQueue[Slot].Transform.HasFlag(HalTransform.Rotate90))
|
|
||||||
{
|
|
||||||
ScaleY = (float)FbHeight / RealHeight;
|
|
||||||
ScaleX = (float)FbWidth / RealWidth;
|
|
||||||
|
|
||||||
OffsY = ((-(float)Crop.Left / Crop.Right) + ScaleX - 1) * -XSign;
|
|
||||||
OffsX = ((-(float)Crop.Top / Crop.Bottom) + ScaleY - 1) * -YSign;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ScaleX = (float)FbWidth / RealWidth;
|
|
||||||
ScaleY = (float)FbHeight / RealHeight;
|
|
||||||
|
|
||||||
OffsX = ((-(float)Crop.Left / Crop.Right) + ScaleX - 1) * XSign;
|
|
||||||
OffsY = ((-(float)Crop.Top / Crop.Bottom) + ScaleY - 1) * -YSign;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ScaleX *= XSign;
|
|
||||||
ScaleY *= YSign;
|
|
||||||
|
|
||||||
float Rotate = 0;
|
|
||||||
|
|
||||||
if (BufferQueue[Slot].Transform.HasFlag(HalTransform.Rotate90))
|
|
||||||
{
|
|
||||||
Rotate = -MathF.PI * 0.5f;
|
|
||||||
}
|
|
||||||
|
|
||||||
Renderer.QueueAction(() => Renderer.FrameBuffer.SetTransform(ScaleX, ScaleY, Rotate, OffsX, OffsY));
|
|
||||||
|
|
||||||
//TODO: Support double buffering here aswell, it is broken for GPU
|
//TODO: Support double buffering here aswell, it is broken for GPU
|
||||||
//frame buffers because it seems to be completely out of sync.
|
//frame buffers because it seems to be completely out of sync.
|
||||||
|
|
Loading…
Reference in a new issue