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; } } }