aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx.Graphics.OpenGL/DrawTextureEmulation.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Ryujinx.Graphics.OpenGL/DrawTextureEmulation.cs')
-rw-r--r--src/Ryujinx.Graphics.OpenGL/DrawTextureEmulation.cs138
1 files changed, 138 insertions, 0 deletions
diff --git a/src/Ryujinx.Graphics.OpenGL/DrawTextureEmulation.cs b/src/Ryujinx.Graphics.OpenGL/DrawTextureEmulation.cs
new file mode 100644
index 00000000..509e20fe
--- /dev/null
+++ b/src/Ryujinx.Graphics.OpenGL/DrawTextureEmulation.cs
@@ -0,0 +1,138 @@
+using OpenTK.Graphics.OpenGL;
+using Ryujinx.Graphics.OpenGL.Image;
+using System;
+
+namespace Ryujinx.Graphics.OpenGL
+{
+ class DrawTextureEmulation
+ {
+ private const string VertexShader = @"#version 430 core
+
+uniform float srcX0;
+uniform float srcY0;
+uniform float srcX1;
+uniform float srcY1;
+
+layout (location = 0) out vec2 texcoord;
+
+void main()
+{
+ bool x1 = (gl_VertexID & 1) != 0;
+ bool y1 = (gl_VertexID & 2) != 0;
+ gl_Position = vec4(x1 ? 1 : -1, y1 ? -1 : 1, 0, 1);
+ texcoord = vec2(x1 ? srcX1 : srcX0, y1 ? srcY1 : srcY0);
+}";
+
+ private const string FragmentShader = @"#version 430 core
+
+layout (location = 0) uniform sampler2D tex;
+
+layout (location = 0) in vec2 texcoord;
+layout (location = 0) out vec4 colour;
+
+void main()
+{
+ colour = texture(tex, texcoord);
+}";
+
+ private int _vsHandle;
+ private int _fsHandle;
+ private int _programHandle;
+ private int _uniformSrcX0Location;
+ private int _uniformSrcY0Location;
+ private int _uniformSrcX1Location;
+ private int _uniformSrcY1Location;
+ private bool _initialized;
+
+ public void Draw(
+ TextureView texture,
+ Sampler sampler,
+ float x0,
+ float y0,
+ float x1,
+ float y1,
+ float s0,
+ float t0,
+ float s1,
+ float t1)
+ {
+ EnsureInitialized();
+
+ GL.UseProgram(_programHandle);
+
+ texture.Bind(0);
+ sampler.Bind(0);
+
+ if (x0 > x1)
+ {
+ float temp = s0;
+ s0 = s1;
+ s1 = temp;
+ }
+
+ if (y0 > y1)
+ {
+ float temp = t0;
+ t0 = t1;
+ t1 = temp;
+ }
+
+ GL.Uniform1(_uniformSrcX0Location, s0);
+ GL.Uniform1(_uniformSrcY0Location, t0);
+ GL.Uniform1(_uniformSrcX1Location, s1);
+ GL.Uniform1(_uniformSrcY1Location, t1);
+
+ GL.ViewportIndexed(0, MathF.Min(x0, x1), MathF.Min(y0, y1), MathF.Abs(x1 - x0), MathF.Abs(y1 - y0));
+
+ GL.DrawArrays(PrimitiveType.TriangleStrip, 0, 4);
+ }
+
+ private void EnsureInitialized()
+ {
+ if (_initialized)
+ {
+ return;
+ }
+
+ _initialized = true;
+
+ _vsHandle = GL.CreateShader(ShaderType.VertexShader);
+ _fsHandle = GL.CreateShader(ShaderType.FragmentShader);
+
+ GL.ShaderSource(_vsHandle, VertexShader);
+ GL.ShaderSource(_fsHandle, FragmentShader);
+
+ GL.CompileShader(_vsHandle);
+ GL.CompileShader(_fsHandle);
+
+ _programHandle = GL.CreateProgram();
+
+ GL.AttachShader(_programHandle, _vsHandle);
+ GL.AttachShader(_programHandle, _fsHandle);
+
+ GL.LinkProgram(_programHandle);
+
+ GL.DetachShader(_programHandle, _vsHandle);
+ GL.DetachShader(_programHandle, _fsHandle);
+
+ _uniformSrcX0Location = GL.GetUniformLocation(_programHandle, "srcX0");
+ _uniformSrcY0Location = GL.GetUniformLocation(_programHandle, "srcY0");
+ _uniformSrcX1Location = GL.GetUniformLocation(_programHandle, "srcX1");
+ _uniformSrcY1Location = GL.GetUniformLocation(_programHandle, "srcY1");
+ }
+
+ public void Dispose()
+ {
+ if (!_initialized)
+ {
+ return;
+ }
+
+ GL.DeleteShader(_vsHandle);
+ GL.DeleteShader(_fsHandle);
+ GL.DeleteProgram(_programHandle);
+
+ _initialized = false;
+ }
+ }
+}