diff options
Diffstat (limited to 'src/Ryujinx.Graphics.OpenGL/DrawTextureEmulation.cs')
-rw-r--r-- | src/Ryujinx.Graphics.OpenGL/DrawTextureEmulation.cs | 138 |
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; + } + } +} |