File: kawase.cpp

package info (click to toggle)
wayfire 0.10.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 3,764 kB
  • sloc: cpp: 52,464; xml: 2,987; ansic: 699; makefile: 161
file content (147 lines) | stat: -rw-r--r-- 4,476 bytes parent folder | download
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
139
140
141
142
143
144
145
146
147
#include "blur.hpp"

static const char *kawase_vertex_shader =
    R"(
#version 100
attribute highp vec2 position;

varying highp vec2 uv;

void main() {
    gl_Position = vec4(position.xy, 0.0, 1.0);
    uv = (position.xy + vec2(1.0, 1.0)) / 2.0;
})";

static const char *kawase_fragment_shader_down =
    R"(
#version 100
precision highp float;

uniform float offset;
uniform vec2 halfpixel;
uniform sampler2D bg_texture;

varying highp vec2 uv;

void main()
{
    vec4 sum = texture2D(bg_texture, uv) * 4.0;
    sum += texture2D(bg_texture, uv - halfpixel.xy * offset);
    sum += texture2D(bg_texture, uv + halfpixel.xy * offset);
    sum += texture2D(bg_texture, uv + vec2(halfpixel.x, -halfpixel.y) * offset);
    sum += texture2D(bg_texture, uv - vec2(halfpixel.x, -halfpixel.y) * offset);
    gl_FragColor = sum / 8.0;
})";

static const char *kawase_fragment_shader_up =
    R"(
#version 100
precision highp float;

uniform float offset;
uniform vec2 halfpixel;
uniform sampler2D bg_texture;

varying highp vec2 uv;

void main()
{
    vec4 sum = texture2D(bg_texture, uv + vec2(-halfpixel.x * 2.0, 0.0) * offset);
    sum += texture2D(bg_texture, uv + vec2(-halfpixel.x, halfpixel.y) * offset) * 2.0;
    sum += texture2D(bg_texture, uv + vec2(0.0, halfpixel.y * 2.0) * offset);
    sum += texture2D(bg_texture, uv + vec2(halfpixel.x, halfpixel.y) * offset) * 2.0;
    sum += texture2D(bg_texture, uv + vec2(halfpixel.x * 2.0, 0.0) * offset);
    sum += texture2D(bg_texture, uv + vec2(halfpixel.x, -halfpixel.y) * offset) * 2.0;
    sum += texture2D(bg_texture, uv + vec2(0.0, -halfpixel.y * 2.0) * offset);
    sum += texture2D(bg_texture, uv + vec2(-halfpixel.x, -halfpixel.y) * offset) * 2.0;
    gl_FragColor = sum / 12.0;
})";

class wf_kawase_blur : public wf_blur_base
{
  public:
    wf_kawase_blur() : wf_blur_base("kawase")
    {
        wf::gles::run_in_context_if_gles([&]
        {
            program[0].set_simple(OpenGL::compile_program(kawase_vertex_shader,
                kawase_fragment_shader_down));
            program[1].set_simple(OpenGL::compile_program(kawase_vertex_shader,
                kawase_fragment_shader_up));
        });
    }

    int blur_fb0(const wf::region_t& blur_region, int width, int height) override
    {
        int iterations = iterations_opt;
        float offset = offset_opt;
        int sampleWidth, sampleHeight;

        /* Upload data to shader */
        static const float vertexData[] = {
            -1.0f, -1.0f,
            1.0f, -1.0f,
            1.0f, 1.0f,
            -1.0f, 1.0f
        };

        program[0].use(wf::TEXTURE_TYPE_RGBA);

        /* Downsample */
        program[0].attrib_pointer("position", 2, 0, vertexData);
        /* Disable blending, because we may have transparent background, which
         * we want to render on uncleared framebuffer */
        GL_CALL(glDisable(GL_BLEND));
        program[0].uniform1f("offset", offset);

        for (int i = 0; i < iterations; i++)
        {
            sampleWidth  = width / (1 << i);
            sampleHeight = height / (1 << i);

            auto region = blur_region * (1.0 / (1 << i));

            program[0].uniform2f("halfpixel",
                0.5f / sampleWidth, 0.5f / sampleHeight);
            render_iteration(region, fb[i % 2], fb[1 - i % 2], sampleWidth,
                sampleHeight);
        }

        program[0].deactivate();

        /* Upsample */
        program[1].use(wf::TEXTURE_TYPE_RGBA);
        program[1].attrib_pointer("position", 2, 0, vertexData);
        program[1].uniform1f("offset", offset);
        for (int i = iterations - 1; i >= 0; i--)
        {
            sampleWidth  = width / (1 << i);
            sampleHeight = height / (1 << i);

            auto region = blur_region * (1.0 / (1 << i));

            program[1].uniform2f("halfpixel",
                0.5f / sampleWidth, 0.5f / sampleHeight);
            render_iteration(region, fb[1 - i % 2], fb[i % 2], sampleWidth,
                sampleHeight);
        }

        /* Reset gl state */
        GL_CALL(glEnable(GL_BLEND));
        GL_CALL(glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA));

        program[1].deactivate();
        GL_CALL(glBindTexture(GL_TEXTURE_2D, 0));
        return 0;
    }

    int calculate_blur_radius() override
    {
        return pow(2, iterations_opt + 1) * offset_opt * degrade_opt;
    }
};

std::unique_ptr<wf_blur_base> create_kawase_blur()
{
    return std::make_unique<wf_kawase_blur>();
}