aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.OpenGL/DrawTextureEmulation.cs
blob: 509e20fe2534ff59f75c0ee7fbbc2b2faa3c933e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
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;
        }
    }
}