~ubuntu-branches/ubuntu/wily/mir/wily-proposed

« back to all changes in this revision

Viewing changes to playground/image_renderer.cpp

  • Committer: Package Import Robot
  • Author(s): Ubuntu daily release
  • Date: 2014-10-10 14:01:26 UTC
  • mto: This revision was merged to the branch mainline in revision 84.
  • Revision ID: package-import@ubuntu.com-20141010140126-n1czko8na1kuz4ll
Tags: upstream-0.8.0+14.10.20141010
ImportĀ upstreamĀ versionĀ 0.8.0+14.10.20141010

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright Ā© 2012 Canonical Ltd.
 
3
 *
 
4
 * This program is free software: you can redistribute it and/or modify
 
5
 * it under the terms of the GNU General Public License version 3 as
 
6
 * published by the Free Software Foundation.
 
7
 *
 
8
 * This program is distributed in the hope that it will be useful,
 
9
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
 * GNU General Public License for more details.
 
12
 *
 
13
 * You should have received a copy of the GNU General Public License
 
14
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
15
 *
 
16
 * Authored by: Alexandros Frantzis <alexandros.frantzis@canonical.com>
 
17
 */
 
18
 
 
19
#include "image_renderer.h"
 
20
 
 
21
// Unfortunately we have to ignore warnings/errors in 3rd party code.
 
22
#pragma GCC diagnostic push
 
23
#pragma GCC diagnostic warning "-Wall"
 
24
#include <glm/glm.hpp>
 
25
#pragma GCC diagnostic pop
 
26
#define GLM_FORCE_RADIANS
 
27
#include <glm/gtc/type_ptr.hpp>
 
28
 
 
29
#include <memory>
 
30
#include <vector>
 
31
 
 
32
#include <boost/throw_exception.hpp>
 
33
#include <stdexcept>
 
34
 
 
35
namespace mt = mir::tools;
 
36
 
 
37
namespace
 
38
{
 
39
 
 
40
const GLchar* vertex_shader_src =
 
41
{
 
42
    "attribute vec3 position;\n"
 
43
    "varying vec2 v_texcoord;\n"
 
44
    "void main() {\n"
 
45
    "   gl_Position = vec4(position, 1.0);\n"
 
46
    "   v_texcoord = position.xy * 0.5 + 0.5;\n"
 
47
    "}\n"
 
48
};
 
49
 
 
50
const GLchar* fragment_shader_src =
 
51
{
 
52
    "precision mediump float;\n"
 
53
    "uniform sampler2D tex;\n"
 
54
    "varying vec2 v_texcoord;\n"
 
55
    "void main() {\n"
 
56
    "   gl_FragColor = texture2D(tex, v_texcoord);\n"
 
57
    "}\n"
 
58
};
 
59
 
 
60
 
 
61
glm::vec3 vertex_attribs[4] =
 
62
{
 
63
    glm::vec3{-1.0f, 1.0f, 0.0f},
 
64
    glm::vec3{-1.0f, -1.0f, 0.0f},
 
65
    glm::vec3{1.0f, 1.0f, 0.0f},
 
66
    glm::vec3{1.0f, -1.0f, 0.0f}
 
67
};
 
68
 
 
69
typedef void(*MirGLGetObjectInfoLog)(GLuint, GLsizei, GLsizei *, GLchar *);
 
70
typedef void(*MirGLGetObjectiv)(GLuint, GLenum, GLint *);
 
71
 
 
72
void throw_with_object_log(MirGLGetObjectInfoLog getObjectInfoLog,
 
73
                           MirGLGetObjectiv      getObjectiv,
 
74
                           std::string const &   msg,
 
75
                           GLuint                object)
 
76
{
 
77
    GLint object_log_length = 0;
 
78
    (*getObjectiv)(object, GL_INFO_LOG_LENGTH, &object_log_length);
 
79
 
 
80
    GLuint const object_log_buffer_length = object_log_length + 1;
 
81
    std::vector<char> log_chars(object_log_buffer_length);
 
82
 
 
83
    (*getObjectInfoLog)(object, object_log_buffer_length, NULL, log_chars.data());
 
84
 
 
85
    std::string object_info_err(msg + "\n");
 
86
    object_info_err.append(log_chars.begin(), log_chars.end() - 1);
 
87
 
 
88
    BOOST_THROW_EXCEPTION(std::runtime_error(object_info_err));
 
89
}
 
90
 
 
91
class GLState
 
92
{
 
93
public:
 
94
    GLState(GLint attrib_loc)
 
95
        : attrib_loc{attrib_loc}
 
96
    {
 
97
        glGetIntegerv(GL_CURRENT_PROGRAM, &program);
 
98
        glGetIntegerv(GL_TEXTURE_BINDING_2D, &texture);
 
99
        glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &buffer);
 
100
        glGetIntegerv(GL_ACTIVE_TEXTURE, &active_texture_unit);
 
101
        if (attrib_loc >= 0)
 
102
        {
 
103
            glGetVertexAttribiv(attrib_loc, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &attrib_enabled);
 
104
            glGetVertexAttribiv(attrib_loc, GL_VERTEX_ATTRIB_ARRAY_SIZE, &attrib_size);
 
105
            glGetVertexAttribiv(attrib_loc, GL_VERTEX_ATTRIB_ARRAY_TYPE, &attrib_type);
 
106
            glGetVertexAttribiv(attrib_loc, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, &attrib_normalized);
 
107
            glGetVertexAttribiv(attrib_loc, GL_VERTEX_ATTRIB_ARRAY_STRIDE, &attrib_stride);
 
108
            glGetVertexAttribPointerv(attrib_loc, GL_VERTEX_ATTRIB_ARRAY_POINTER, &attrib_pointer);
 
109
        }
 
110
    }
 
111
 
 
112
    GLState() : GLState{invalid_attrib_loc} {}
 
113
 
 
114
    ~GLState()
 
115
    {
 
116
        glUseProgram(program);
 
117
        glBindTexture(GL_TEXTURE_2D, texture);
 
118
        glBindBuffer(GL_ARRAY_BUFFER, buffer);
 
119
        glActiveTexture(active_texture_unit);
 
120
        if (attrib_loc >= 0)
 
121
        {
 
122
            glVertexAttribPointer(attrib_loc, attrib_size, attrib_type,
 
123
                                  attrib_normalized, attrib_stride, attrib_pointer);
 
124
            if (attrib_enabled)
 
125
                glEnableVertexAttribArray(attrib_loc);
 
126
            else
 
127
                glDisableVertexAttribArray(attrib_loc);
 
128
        }
 
129
    }
 
130
 
 
131
private:
 
132
    static GLint const invalid_attrib_loc = -1;
 
133
    GLint program = 0;
 
134
    GLint texture = 0;
 
135
    GLint buffer = 0;
 
136
    GLint active_texture_unit = 0;
 
137
    GLint attrib_loc = invalid_attrib_loc;
 
138
    GLint attrib_enabled = 0;
 
139
    GLint attrib_size = 0;
 
140
    GLint attrib_type = 0;
 
141
    GLint attrib_normalized = 0;
 
142
    GLint attrib_stride = 0;
 
143
    GLvoid* attrib_pointer = nullptr;
 
144
};
 
145
 
 
146
}
 
147
 
 
148
mt::ImageRenderer::ImageRenderer(const uint8_t* pixel_data, mir::geometry::Size size,
 
149
                                 uint32_t bytes_per_pixel)
 
150
{
 
151
    GLState gl_state;
 
152
 
 
153
    resources.setup();
 
154
 
 
155
    /* Upload the texture */
 
156
    glBindTexture(GL_TEXTURE_2D, resources.texture);
 
157
 
 
158
    GLenum format = (bytes_per_pixel == 3) ? GL_RGB : GL_RGBA;
 
159
 
 
160
    glTexImage2D(GL_TEXTURE_2D, 0, format,
 
161
                 size.width.as_uint32_t(), size.height.as_uint32_t(), 0,
 
162
                 format, GL_UNSIGNED_BYTE, pixel_data);
 
163
}
 
164
 
 
165
mt::ImageRenderer::Resources::~Resources()
 
166
{
 
167
    if (vertex_shader)
 
168
        glDeleteShader(vertex_shader);
 
169
    if (fragment_shader)
 
170
        glDeleteShader(fragment_shader);
 
171
    if (program)
 
172
        glDeleteProgram(program);
 
173
    if (vertex_attribs_vbo)
 
174
        glDeleteBuffers(1, &vertex_attribs_vbo);
 
175
    if (texture)
 
176
        glDeleteTextures(1, &texture);
 
177
}
 
178
 
 
179
void mt::ImageRenderer::Resources::setup()
 
180
{
 
181
    GLint param = 0;
 
182
 
 
183
    /* Create shaders and program */
 
184
    vertex_shader = glCreateShader(GL_VERTEX_SHADER);
 
185
    glShaderSource(vertex_shader, 1, &vertex_shader_src, 0);
 
186
    glCompileShader(vertex_shader);
 
187
    glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &param);
 
188
    if (param == GL_FALSE)
 
189
    {
 
190
        throw_with_object_log(glGetShaderInfoLog, glGetShaderiv,
 
191
                              "Failed to compile vertex shader:",
 
192
                              vertex_shader);
 
193
    }
 
194
 
 
195
    fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
 
196
    glShaderSource(fragment_shader, 1, &fragment_shader_src, 0);
 
197
    glCompileShader(fragment_shader);
 
198
    glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &param);
 
199
    if (param == GL_FALSE)
 
200
    {
 
201
        throw_with_object_log(glGetShaderInfoLog, glGetShaderiv,
 
202
                              "Failed to compile fragment shader:",
 
203
                              fragment_shader);
 
204
    }
 
205
 
 
206
    program = glCreateProgram();
 
207
    glAttachShader(program, vertex_shader);
 
208
    glAttachShader(program, fragment_shader);
 
209
    glLinkProgram(program);
 
210
    glGetProgramiv(program, GL_LINK_STATUS, &param);
 
211
    if (param == GL_FALSE)
 
212
    {
 
213
        throw_with_object_log(glGetProgramInfoLog, glGetProgramiv,
 
214
                              "Failed to link shader program:",
 
215
                              program);
 
216
    }
 
217
 
 
218
    glUseProgram(program);
 
219
 
 
220
    /* Set up program variables */
 
221
    GLint tex_loc = glGetUniformLocation(program, "tex");
 
222
    position_attr_loc = glGetAttribLocation(program, "position");
 
223
 
 
224
    /* Create the texture */
 
225
    glGenTextures(1, &texture);
 
226
    glBindTexture(GL_TEXTURE_2D, texture);
 
227
 
 
228
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
 
229
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 
230
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
 
231
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 
232
 
 
233
    glUniform1i(tex_loc, 0);
 
234
 
 
235
    /* Create VBO */
 
236
    glGenBuffers(1, &vertex_attribs_vbo);
 
237
 
 
238
    glBindBuffer(GL_ARRAY_BUFFER, vertex_attribs_vbo);
 
239
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_attribs),
 
240
                 glm::value_ptr(vertex_attribs[0]), GL_STATIC_DRAW);
 
241
}
 
242
 
 
243
 
 
244
void mt::ImageRenderer::render()
 
245
{
 
246
    GLState gl_state(resources.position_attr_loc);
 
247
 
 
248
    glUseProgram(resources.program);
 
249
 
 
250
    glActiveTexture(GL_TEXTURE0);
 
251
 
 
252
    /* Set up vertex attribute data */
 
253
    glBindBuffer(GL_ARRAY_BUFFER, resources.vertex_attribs_vbo);
 
254
    glVertexAttribPointer(resources.position_attr_loc, 3, GL_FLOAT, GL_FALSE, 0, 0);
 
255
 
 
256
    glBindTexture(GL_TEXTURE_2D, resources.texture);
 
257
 
 
258
    /* Draw */
 
259
    glEnableVertexAttribArray(resources.position_attr_loc);
 
260
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
 
261
}