~raof/mir/prober-drm-device-probe

« back to all changes in this revision

Viewing changes to tests/unit-tests/graphics/test_gl_renderer.cpp

  • Committer: Kevin DuBois
  • Date: 2012-11-13 01:36:29 UTC
  • mfrom: (245 trunk)
  • mto: This revision was merged to the branch mainline in revision 246.
  • Revision ID: kevin.dubois@canonical.com-20121113013629-q4496w4mp5e33auk
merge in base branch. move the demo clients to a new directory, examples/

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: Sam Spilsbury <sam.spilsbury@canonical.com>
 
17
 */
 
18
 
 
19
#include <functional>
 
20
#include <string>
 
21
#include <cstring>
 
22
#include <stdexcept>
 
23
#include <gtest/gtest.h>
 
24
#include <gmock/gmock.h>
 
25
#include <mir/geometry/size.h>
 
26
#include <mir/graphics/gl_renderer.h>
 
27
#include <mir/graphics/renderable.h>
 
28
#include <mir/compositor/graphic_region.h>
 
29
#include <mir_test/gl_mock.h>
 
30
 
 
31
using testing::SetArgPointee;
 
32
using testing::InSequence;
 
33
using testing::Return;
 
34
using testing::_;
 
35
 
 
36
namespace mc=mir::compositor;
 
37
namespace mg=mir::graphics;
 
38
 
 
39
namespace
 
40
{
 
41
 
 
42
const GLint stub_bad_shader = 0;
 
43
const GLint stub_bad_program = 0;
 
44
const GLint stub_v_shader = 1;
 
45
const GLint stub_f_shader = 2;
 
46
const GLint stub_program = 1;
 
47
const GLint stub_vbo = 1;
 
48
const GLint stub_texture = 1;
 
49
const GLint transform_uniform_location = 1;
 
50
const GLint alpha_uniform_location = 2;
 
51
const GLint position_attr_location = 3;
 
52
const GLint texcoord_attr_location = 4;
 
53
const GLint screen_to_gl_coords_uniform_location = 5;
 
54
const GLint tex_uniform_location = 6;
 
55
const std::string stub_info_log = "something failed!";
 
56
const size_t stub_info_log_length = stub_info_log.size();
 
57
const size_t stub_info_log_buffer_length = stub_info_log_length + 1;
 
58
 
 
59
void ExpectShaderCompileFailure(const GLint shader, mir::GLMock &gl_mock)
 
60
{
 
61
    EXPECT_CALL(gl_mock, glGetShaderiv(shader, GL_COMPILE_STATUS, _))
 
62
        .WillOnce(SetArgPointee<2>(GL_FALSE));
 
63
}
 
64
 
 
65
void ExpectShaderCompileSuccess(const GLint shader, mir::GLMock &gl_mock)
 
66
{
 
67
    EXPECT_CALL(gl_mock, glGetShaderiv(shader, GL_COMPILE_STATUS, _))
 
68
        .WillOnce(SetArgPointee<2>(GL_TRUE));
 
69
}
 
70
 
 
71
void SetUpMockVertexShader(mir::GLMock &gl_mock, const std::function<void(const GLint, mir::GLMock &)> &shader_compile_expectation)
 
72
{
 
73
    /* Vertex Shader */
 
74
    EXPECT_CALL(gl_mock, glCreateShader(GL_VERTEX_SHADER))
 
75
        .WillOnce(Return(stub_v_shader));
 
76
    EXPECT_CALL(gl_mock, glShaderSource(stub_v_shader, 1, _, 0));
 
77
    EXPECT_CALL(gl_mock, glCompileShader(stub_v_shader));
 
78
    shader_compile_expectation(stub_v_shader, gl_mock);
 
79
}
 
80
 
 
81
void SetUpMockFragmentShader(mir::GLMock &gl_mock, const std::function<void(const GLint, mir::GLMock &)> &shader_compile_expectation)
 
82
{
 
83
    /* Fragment Shader */
 
84
    EXPECT_CALL(gl_mock, glCreateShader(GL_FRAGMENT_SHADER))
 
85
        .WillOnce(Return(stub_f_shader));
 
86
    EXPECT_CALL(gl_mock, glShaderSource(stub_f_shader, 1, _, 0));
 
87
    EXPECT_CALL(gl_mock, glCompileShader(stub_f_shader));
 
88
    shader_compile_expectation(stub_f_shader, gl_mock);
 
89
}
 
90
 
 
91
void ExpectProgramLinkFailure(const GLint program, mir::GLMock &gl_mock)
 
92
{
 
93
    EXPECT_CALL(gl_mock, glGetProgramiv(program, GL_LINK_STATUS, _))
 
94
        .WillOnce(SetArgPointee<2>(GL_FALSE));
 
95
}
 
96
 
 
97
void ExpectProgramLinkSuccess(const GLint program, mir::GLMock &gl_mock)
 
98
{
 
99
    EXPECT_CALL(gl_mock, glGetProgramiv(program, GL_LINK_STATUS, _))
 
100
        .WillOnce(SetArgPointee<2>(GL_TRUE));
 
101
}
 
102
 
 
103
void SetUpMockGraphicsProgram(mir::GLMock &gl_mock, const std::function<void(const GLint, mir::GLMock &)> &program_link_expectation)
 
104
{
 
105
    /* Graphics Program */
 
106
    EXPECT_CALL(gl_mock, glCreateProgram())
 
107
            .WillOnce(Return(stub_program));
 
108
    EXPECT_CALL(gl_mock, glAttachShader(stub_program, stub_v_shader));
 
109
    EXPECT_CALL(gl_mock, glAttachShader(stub_program, stub_f_shader));
 
110
    EXPECT_CALL(gl_mock, glLinkProgram(stub_program));
 
111
    program_link_expectation(stub_program, gl_mock);
 
112
}
 
113
 
 
114
void SetUpMockProgramData(mir::GLMock &gl_mock)
 
115
{
 
116
    /* Uniforms and Attributes */
 
117
    EXPECT_CALL(gl_mock, glUseProgram(stub_program));
 
118
 
 
119
    EXPECT_CALL(gl_mock, glGetUniformLocation(stub_program, _))
 
120
        .WillOnce(Return(screen_to_gl_coords_uniform_location));
 
121
    EXPECT_CALL(gl_mock, glGetUniformLocation(stub_program, _))
 
122
        .WillOnce(Return(tex_uniform_location));
 
123
    EXPECT_CALL(gl_mock, glGetUniformLocation(stub_program, _))
 
124
        .WillOnce(Return(transform_uniform_location));
 
125
    EXPECT_CALL(gl_mock, glGetUniformLocation(stub_program, _))
 
126
        .WillOnce(Return(alpha_uniform_location));
 
127
    EXPECT_CALL(gl_mock, glGetAttribLocation(stub_program, _))
 
128
        .WillOnce(Return(position_attr_location));
 
129
    EXPECT_CALL(gl_mock, glGetAttribLocation(stub_program, _))
 
130
        .WillOnce(Return(texcoord_attr_location));
 
131
 
 
132
    EXPECT_CALL(gl_mock, glUniformMatrix4fv(screen_to_gl_coords_uniform_location, 1, GL_FALSE, _));
 
133
}
 
134
 
 
135
void SetUpMockRenderTexture(mir::GLMock &gl_mock)
 
136
{
 
137
    /* Set up the render texture */
 
138
    EXPECT_CALL(gl_mock, glGenTextures(1, _))
 
139
        .WillOnce(SetArgPointee<1>(stub_texture));
 
140
    EXPECT_CALL(gl_mock, glBindTexture(GL_TEXTURE_2D, stub_texture));
 
141
    EXPECT_CALL(gl_mock, glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
 
142
    EXPECT_CALL(gl_mock, glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
 
143
    EXPECT_CALL(gl_mock, glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
 
144
    EXPECT_CALL(gl_mock, glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
 
145
}
 
146
 
 
147
void FillMockVertexBuffer(mir::GLMock &gl_mock)
 
148
{
 
149
    /* Set up VBO */
 
150
    EXPECT_CALL(gl_mock, glGenBuffers(1, _))
 
151
        .WillOnce(SetArgPointee<1>(stub_vbo));
 
152
    EXPECT_CALL(gl_mock, glBindBuffer(GL_ARRAY_BUFFER, stub_vbo));
 
153
    EXPECT_CALL(gl_mock, glBufferData(GL_ARRAY_BUFFER, _, _, GL_STATIC_DRAW));
 
154
 
 
155
    /* These should go away */
 
156
    EXPECT_CALL(gl_mock, glBindBuffer(GL_ARRAY_BUFFER, 0));
 
157
    EXPECT_CALL(gl_mock, glUseProgram(0));
 
158
}
 
159
 
 
160
class GLRendererSetupProcess :
 
161
    public testing::Test
 
162
{
 
163
public:
 
164
 
 
165
    mir::GLMock gl_mock;
 
166
    mir::geometry::Size display_size;
 
167
};
 
168
 
 
169
ACTION_P2(CopyString, str, len)
 
170
{
 
171
    memcpy(arg3, str, len);
 
172
    arg3[len] = '\0';
 
173
}
 
174
 
 
175
ACTION_P(ReturnByConstReference, cref)
 
176
{
 
177
    return cref;
 
178
}
 
179
 
 
180
MATCHER_P(NthCharacterIsNul, n, "specified character is the nul-byte")
 
181
{
 
182
    return arg[n] == '\0';
 
183
}
 
184
 
 
185
TEST_F(GLRendererSetupProcess, vertex_shader_compiler_failure_recovers_and_throws)
 
186
{
 
187
    using namespace std::placeholders;
 
188
 
 
189
    SetUpMockVertexShader(gl_mock, std::bind(ExpectShaderCompileFailure, _1, _2));
 
190
 
 
191
    EXPECT_CALL(gl_mock, glGetShaderiv(stub_v_shader, GL_INFO_LOG_LENGTH, _))
 
192
        .WillOnce(SetArgPointee<2>(stub_info_log_length));
 
193
    EXPECT_CALL(gl_mock, glGetShaderInfoLog(stub_v_shader,
 
194
        stub_info_log_length,
 
195
        _,
 
196
        NthCharacterIsNul(stub_info_log_length)))
 
197
            .WillOnce(CopyString(stub_info_log.c_str(),
 
198
                stub_info_log.size()));
 
199
 
 
200
    EXPECT_THROW({
 
201
    std::unique_ptr<mg::GLRenderer> r;
 
202
    r.reset(new mg::GLRenderer(display_size));
 
203
    }, std::runtime_error);
 
204
}
 
205
 
 
206
TEST_F(GLRendererSetupProcess, fragment_shader_compiler_failure_recovers_and_throw)
 
207
{
 
208
    using namespace std::placeholders;
 
209
 
 
210
    SetUpMockVertexShader(gl_mock, std::bind(ExpectShaderCompileSuccess, _1, _2));
 
211
    SetUpMockFragmentShader(gl_mock, std::bind(ExpectShaderCompileFailure, _1, _2));
 
212
 
 
213
    EXPECT_CALL(gl_mock, glGetShaderiv(stub_f_shader, GL_INFO_LOG_LENGTH, _))
 
214
        .WillOnce(SetArgPointee<2>(stub_info_log_length));
 
215
    EXPECT_CALL(gl_mock, glGetShaderInfoLog(stub_f_shader,
 
216
        stub_info_log_length,
 
217
        _,
 
218
        NthCharacterIsNul(stub_info_log_length)))
 
219
            .WillOnce(CopyString(stub_info_log.c_str(),
 
220
                stub_info_log.size()));
 
221
 
 
222
    EXPECT_THROW({
 
223
        std::unique_ptr<mg::GLRenderer> r;
 
224
        r.reset(new mg::GLRenderer(display_size));
 
225
    }, std::runtime_error);
 
226
}
 
227
 
 
228
TEST_F(GLRendererSetupProcess, graphics_program_linker_failure_recovers_and_throw)
 
229
{
 
230
    using namespace std::placeholders;
 
231
 
 
232
    SetUpMockVertexShader(gl_mock, std::bind(ExpectShaderCompileSuccess, _1, _2));
 
233
    SetUpMockFragmentShader(gl_mock, std::bind(ExpectShaderCompileSuccess, _1, _2));
 
234
    SetUpMockGraphicsProgram(gl_mock, std::bind(ExpectProgramLinkFailure, _1, _2));
 
235
 
 
236
    EXPECT_CALL(gl_mock, glGetProgramiv(stub_program, GL_INFO_LOG_LENGTH, _))
 
237
            .WillOnce(SetArgPointee<2>(stub_info_log_length));
 
238
    EXPECT_CALL(gl_mock, glGetProgramInfoLog(stub_program,
 
239
        stub_info_log_length,
 
240
        _,
 
241
        NthCharacterIsNul(stub_info_log_length)))
 
242
            .WillOnce(CopyString(stub_info_log.c_str(),
 
243
                stub_info_log.size()));
 
244
 
 
245
    EXPECT_THROW({
 
246
        std::unique_ptr<mg::GLRenderer> r;
 
247
        r.reset(new mg::GLRenderer(display_size));
 
248
    }, std::runtime_error);
 
249
}
 
250
 
 
251
class GLRenderer :
 
252
    public testing::Test
 
253
{
 
254
public:
 
255
 
 
256
    GLRenderer()
 
257
    {
 
258
        using namespace std::placeholders;
 
259
 
 
260
        InSequence s;
 
261
 
 
262
        SetUpMockVertexShader(gl_mock, std::bind(ExpectShaderCompileSuccess, _1, _2));
 
263
        SetUpMockFragmentShader(gl_mock, std::bind(ExpectShaderCompileSuccess, _1, _2));
 
264
        SetUpMockGraphicsProgram(gl_mock, std::bind(ExpectProgramLinkSuccess, _1,_2));
 
265
        SetUpMockProgramData(gl_mock);
 
266
        SetUpMockRenderTexture(gl_mock);
 
267
        EXPECT_CALL(gl_mock, glUniform1i(tex_uniform_location, 0));
 
268
        FillMockVertexBuffer(gl_mock);
 
269
 
 
270
        renderer.reset(new mg::GLRenderer(display_size));
 
271
    }
 
272
 
 
273
    mir::GLMock         gl_mock;
 
274
    mir::geometry::Size display_size;
 
275
    std::unique_ptr<mg::GLRenderer> renderer;
 
276
};
 
277
 
 
278
class MockRenderable :
 
279
    public mg::Renderable
 
280
{
 
281
public:
 
282
 
 
283
    MOCK_CONST_METHOD0(top_left, mir::geometry::Point());
 
284
    MOCK_CONST_METHOD0(size, mir::geometry::Size());
 
285
    MOCK_CONST_METHOD0(texture, std::shared_ptr<mc::GraphicRegion>());
 
286
    MOCK_CONST_METHOD0(transformation, glm::mat4());
 
287
    MOCK_CONST_METHOD0(alpha, float());
 
288
    MOCK_CONST_METHOD0(hidden, bool());
 
289
};
 
290
 
 
291
class MockGraphicRegion :
 
292
    public mc::GraphicRegion
 
293
{
 
294
public:
 
295
 
 
296
    MOCK_CONST_METHOD0(size, mir::geometry::Size());
 
297
    MOCK_CONST_METHOD0(stride, mir::geometry::Stride());
 
298
    MOCK_CONST_METHOD0(pixel_format, mir::geometry::PixelFormat());
 
299
    MOCK_METHOD0(bind_to_texture, void());
 
300
};
 
301
 
 
302
void NullGraphicRegionDeleter(MockGraphicRegion * /* gr */)
 
303
{
 
304
}
 
305
 
 
306
}
 
307
 
 
308
TEST_F(GLRenderer, TestSetUpRenderContextBeforeRenderingRenderable)
 
309
{
 
310
    using namespace std::placeholders;
 
311
 
 
312
    MockRenderable rd;
 
313
    MockGraphicRegion gr;
 
314
    std::shared_ptr<MockGraphicRegion> gr_ptr(&gr, std::bind(NullGraphicRegionDeleter, _1));
 
315
    mir::geometry::Point tl;
 
316
    mir::geometry::Size  s;
 
317
    glm::mat4            transformation;
 
318
 
 
319
    tl.x = mir::geometry::X(1);
 
320
    tl.y = mir::geometry::Y(2);
 
321
 
 
322
    s.width = mir::geometry::Width(10);
 
323
    s.height = mir::geometry::Height(20);
 
324
 
 
325
    InSequence seq;
 
326
 
 
327
    EXPECT_CALL(rd, top_left()).WillOnce(Return(tl));
 
328
    EXPECT_CALL(rd, size()).WillOnce(Return(s));
 
329
 
 
330
    EXPECT_CALL(gl_mock, glUseProgram(stub_program));
 
331
    EXPECT_CALL(gl_mock, glEnable(GL_BLEND));
 
332
    EXPECT_CALL(gl_mock, glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
 
333
    EXPECT_CALL(gl_mock, glActiveTexture(GL_TEXTURE0));
 
334
 
 
335
    EXPECT_CALL(rd, transformation())
 
336
        .WillOnce(Return(transformation));
 
337
    EXPECT_CALL(gl_mock, glUniformMatrix4fv(transform_uniform_location, 1, GL_FALSE, _));
 
338
    EXPECT_CALL(rd, alpha())
 
339
        .WillOnce(Return(0));
 
340
    EXPECT_CALL(gl_mock, glUniform1f(alpha_uniform_location, _));
 
341
    EXPECT_CALL(gl_mock, glBindBuffer(GL_ARRAY_BUFFER, stub_vbo));
 
342
    EXPECT_CALL(gl_mock, glVertexAttribPointer(position_attr_location, 3, GL_FLOAT, GL_FALSE, _, _));
 
343
    EXPECT_CALL(gl_mock, glVertexAttribPointer(texcoord_attr_location, 2, GL_FLOAT, GL_FALSE, _, _));
 
344
 
 
345
    EXPECT_CALL(gl_mock, glBindTexture(GL_TEXTURE_2D, stub_texture));
 
346
 
 
347
    EXPECT_CALL(rd, texture())
 
348
        .WillOnce(Return(gr_ptr));
 
349
    EXPECT_CALL(gr, bind_to_texture());
 
350
 
 
351
    EXPECT_CALL(gl_mock, glEnableVertexAttribArray(position_attr_location));
 
352
    EXPECT_CALL(gl_mock, glEnableVertexAttribArray(texcoord_attr_location));
 
353
 
 
354
    EXPECT_CALL(gl_mock, glDrawArrays(GL_TRIANGLE_STRIP, 0, 4));
 
355
 
 
356
    EXPECT_CALL(gl_mock, glDisableVertexAttribArray(texcoord_attr_location));
 
357
    EXPECT_CALL(gl_mock, glDisableVertexAttribArray(position_attr_location));
 
358
 
 
359
    renderer->render(rd);
 
360
}