2
* Copyright Ā© 2012 Canonical Ltd.
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.
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.
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/>.
16
* Authored by: Alexandros Frantzis <alexandros.frantzis@canonical.com>
19
#include "image_renderer.h"
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>
32
#include <boost/throw_exception.hpp>
35
namespace mt = mir::tools;
40
const GLchar* vertex_shader_src =
42
"attribute vec3 position;\n"
43
"varying vec2 v_texcoord;\n"
45
" gl_Position = vec4(position, 1.0);\n"
46
" v_texcoord = position.xy * 0.5 + 0.5;\n"
50
const GLchar* fragment_shader_src =
52
"precision mediump float;\n"
53
"uniform sampler2D tex;\n"
54
"varying vec2 v_texcoord;\n"
56
" gl_FragColor = texture2D(tex, v_texcoord);\n"
61
glm::vec3 vertex_attribs[4] =
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}
69
typedef void(*MirGLGetObjectInfoLog)(GLuint, GLsizei, GLsizei *, GLchar *);
70
typedef void(*MirGLGetObjectiv)(GLuint, GLenum, GLint *);
72
void throw_with_object_log(MirGLGetObjectInfoLog getObjectInfoLog,
73
MirGLGetObjectiv getObjectiv,
74
std::string const & msg,
77
GLint object_log_length = 0;
78
(*getObjectiv)(object, GL_INFO_LOG_LENGTH, &object_log_length);
80
GLuint const object_log_buffer_length = object_log_length + 1;
81
std::vector<char> log_chars(object_log_buffer_length);
83
(*getObjectInfoLog)(object, object_log_buffer_length, NULL, log_chars.data());
85
std::string object_info_err(msg + "\n");
86
object_info_err.append(log_chars.begin(), log_chars.end() - 1);
88
BOOST_THROW_EXCEPTION(std::runtime_error(object_info_err));
94
GLState(GLint attrib_loc)
95
: attrib_loc{attrib_loc}
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);
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);
112
GLState() : GLState{invalid_attrib_loc} {}
116
glUseProgram(program);
117
glBindTexture(GL_TEXTURE_2D, texture);
118
glBindBuffer(GL_ARRAY_BUFFER, buffer);
119
glActiveTexture(active_texture_unit);
122
glVertexAttribPointer(attrib_loc, attrib_size, attrib_type,
123
attrib_normalized, attrib_stride, attrib_pointer);
125
glEnableVertexAttribArray(attrib_loc);
127
glDisableVertexAttribArray(attrib_loc);
132
static GLint const invalid_attrib_loc = -1;
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;
148
mt::ImageRenderer::ImageRenderer(const uint8_t* pixel_data, mir::geometry::Size size,
149
uint32_t bytes_per_pixel)
155
/* Upload the texture */
156
glBindTexture(GL_TEXTURE_2D, resources.texture);
158
GLenum format = (bytes_per_pixel == 3) ? GL_RGB : GL_RGBA;
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);
165
mt::ImageRenderer::Resources::~Resources()
168
glDeleteShader(vertex_shader);
170
glDeleteShader(fragment_shader);
172
glDeleteProgram(program);
173
if (vertex_attribs_vbo)
174
glDeleteBuffers(1, &vertex_attribs_vbo);
176
glDeleteTextures(1, &texture);
179
void mt::ImageRenderer::Resources::setup()
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, ¶m);
188
if (param == GL_FALSE)
190
throw_with_object_log(glGetShaderInfoLog, glGetShaderiv,
191
"Failed to compile vertex shader:",
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, ¶m);
199
if (param == GL_FALSE)
201
throw_with_object_log(glGetShaderInfoLog, glGetShaderiv,
202
"Failed to compile fragment shader:",
206
program = glCreateProgram();
207
glAttachShader(program, vertex_shader);
208
glAttachShader(program, fragment_shader);
209
glLinkProgram(program);
210
glGetProgramiv(program, GL_LINK_STATUS, ¶m);
211
if (param == GL_FALSE)
213
throw_with_object_log(glGetProgramInfoLog, glGetProgramiv,
214
"Failed to link shader program:",
218
glUseProgram(program);
220
/* Set up program variables */
221
GLint tex_loc = glGetUniformLocation(program, "tex");
222
position_attr_loc = glGetAttribLocation(program, "position");
224
/* Create the texture */
225
glGenTextures(1, &texture);
226
glBindTexture(GL_TEXTURE_2D, texture);
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);
233
glUniform1i(tex_loc, 0);
236
glGenBuffers(1, &vertex_attribs_vbo);
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);
244
void mt::ImageRenderer::render()
246
GLState gl_state(resources.position_attr_loc);
248
glUseProgram(resources.program);
250
glActiveTexture(GL_TEXTURE0);
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);
256
glBindTexture(GL_TEXTURE_2D, resources.texture);
259
glEnableVertexAttribArray(resources.position_attr_loc);
260
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);