Mir

Merge lp:~vanvugt/mir/fix-1350674 into lp:mir

Proposed by Daniel van Vugt
Status: Merged
Approved by: Daniel van Vugt
Approved revision: 2216
Merged at revision: 2209
Proposed branch: lp:~vanvugt/mir/fix-1350674
Merge into: lp:mir
Diff against target: 1016 lines (+341/-177)
18 files modified
playground/demo-shell/demo_compositor.cpp (+0/-2)
playground/demo-shell/demo_compositor.h (+0/-1)
playground/demo-shell/demo_renderer.cpp (+1/-2)
playground/demo-shell/demo_renderer.h (+0/-1)
playground/demo-shell/demo_shell.cpp (+1/-5)
src/include/server/mir/compositor/gl_program_family.h (+67/-0)
src/include/server/mir/compositor/gl_renderer.h (+18/-10)
src/server/compositor/CMakeLists.txt (+1/-0)
src/server/compositor/default_configuration.cpp (+1/-1)
src/server/compositor/gl_program_family.cpp (+105/-0)
src/server/compositor/gl_renderer.cpp (+74/-40)
src/server/compositor/gl_renderer_factory.cpp (+1/-6)
src/server/compositor/gl_renderer_factory.h (+0/-7)
src/server/symbols.map (+1/-0)
tests/unit-tests/compositor/test_gl_renderer.cpp (+27/-65)
tests/unit-tests/examples/test_demo_compositor.cpp (+17/-7)
tests/unit-tests/examples/test_demo_renderer.cpp (+14/-3)
tests/unit-tests/graphics/test_program_factory.cpp (+13/-27)
To merge this branch: bzr merge lp:~vanvugt/mir/fix-1350674
Reviewer Review Type Date Requested Status
Robert Carr (community) Approve
PS Jenkins bot (community) continuous-integration Approve
Kevin DuBois (community) Needs Fixing
Alan Griffiths Approve
Review via email: mp+245508@code.launchpad.net

Commit message

Use a more efficient (optimal!) shader when it's safe (LP: #1350674).

Also clean up more widely and provide a foundation for more custom
shaders in future.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

129 +class GLProgramFamily
130 +{
131 +public:
132 + GLuint add_program(const char* vshader, const char* fshader);
133 + ~GLProgramFamily();

The destructor ought to be noexcept.

Also, I don't think it is useful to support copy/assign semantics.

review: Needs Fixing
Revision history for this message
Robert Carr (robertcarr) wrote :

Seems non harmful excepting Alan's points.

I don't really understand what a GLProgramFamily is though? It seems kind of like a hybrid of a factory and a collection, without really being either. I think I would have gone for something like:

GLProgram {
   GLProgram(vsrc, fsrc)
   Enable()
   Disable)
}

Then you just use a standard collection class.

Revision history for this message
Daniel van Vugt (vanvugt) wrote :

Alan: All fixed.

Robert: GLProgramFamily has several benefits, although I only realised late in the game I could have introduced it separately...

Benefits of introducing GLProgramFamily:
  * It's more efficient: Multiple programs can and do share some shaders (e.g. the vertex shader in GLRenderer).
  * It results in significantly less coupling (no factory required as you can see).
  * It's safer. GLProgram's attempt to use RAII on GL programs would become unsafe when you hit copy constructors (e.g. put them in containers). The new copy then only works up to the point the original copy gets destroyed, and then the new copy stops working. So in order to RAII GLProgram safely, reference counting (and hence more inefficient indirection using the heap and shared pointers) would be required too.

Benefits of not introducing GLProgramFamily:
  * The diff would be smaller for this bug fix.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

The code makes sense, but I don't understand the area enough to be sure it is a good idea.

I see what Robert means about the GLProgramFamily name (which doesn't immediately suggest its role as a cache/factory).

review: Approve
Revision history for this message
Robert Carr (robertcarr) wrote :

GLProgramCache would have avoided the concern yes.

review: Approve
Revision history for this message
Kevin DuBois (kdub) wrote :

needs info:
I have some distant memory of having to introduce GlProgramFactory during the overlay work so that we could protect against race conditions when getting new uniform/shader/etc id's from GLES. Should the demo renderer still use that class? (if I remember, Alexandros was concerned about this)

nits:
127 +namespace mir { namespace compositor {
269 +namespace mir { namespace compositor {
new style of namespaces.

296 +GLProgramFamily::GLProgramFamily()
297 +{
298 +}
why not use default constructor?

137 + GLuint add_program(const char* vshader, const char* fshader);
string?

review: Needs Fixing
Revision history for this message
Daniel van Vugt (vanvugt) wrote :

Kevin:
* The overlay work still uses GLProgramFactory etc. I haven't touched that code here.
* New style namespaces: Yeah I think the new style is more readable. It avoids having multiple "{" at the start of lines without indentation (which is poor for readability).
* Default constructor: That's kind of intentional. If "= default" results in an actual empty constructor getting created inline then this approach is more efficient (less bytes and compiles faster). If "= default" results in the empty constructor not being created at all, then it would indeed be more efficient, but might still compile slower. So given this is something that you only construct once and constructor runtime performance is not the main issue, I think avoiding "= default" has more benefits here.
* string? Yeah I've intentionally used constant character pointers. We only need to support program source that is fixed in memory for the lifetime of the process. Although I wonder if "const char* const" would indicate that better...

Revision history for this message
Daniel van Vugt (vanvugt) wrote :

BTW, the word "Family" as opposed to "Cache" is important. The "Family" part indicates that it is a collection of programs that share shaders. And more loosely in the case of GLRenderer, they use a common pattern of uniform names too. Hence in both cases, it's a "family" and not just a cache.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Robert Carr (robertcarr) wrote :

>> That's kind of intentional. If "= default" results in an actual empty constructor getting created >> inline then this approach is more efficient (less bytes and compiles faster). If "= default" results >> in the empty constructor not being created at all, then it would indeed be more efficient, but might >> still compile slower. So given this is something that you only construct once and constructor
>> runtime performance is not the main issue, I think avoiding "= default" has more benefits here.

The main issue if anything is consistency with the rest of the code base

review: Needs Fixing
Revision history for this message
Daniel van Vugt (vanvugt) wrote :

Robert: I already changed it to the syntax you want some hours before your comment :)

lp:~vanvugt/mir/fix-1350674 updated
2216. By Daniel van Vugt

Merge latest trunk

Revision history for this message
Daniel van Vugt (vanvugt) wrote :

All "Needs Fixings" resolved, or explained.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Robert Carr (robertcarr) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'playground/demo-shell/demo_compositor.cpp'
2--- playground/demo-shell/demo_compositor.cpp 2014-12-18 09:37:22 +0000
3+++ playground/demo-shell/demo_compositor.cpp 2015-01-08 03:41:50 +0000
4@@ -40,14 +40,12 @@
5
6 me::DemoCompositor::DemoCompositor(
7 mg::DisplayBuffer& display_buffer,
8- mg::GLProgramFactory const& factory,
9 std::shared_ptr<mc::CompositorReport> const& report) :
10 display_buffer(display_buffer),
11 report(report),
12 viewport(display_buffer.view_area()),
13 zoom_mag{1.0f},
14 renderer(
15- factory,
16 display_buffer.view_area(),
17 destination_alpha(display_buffer),
18 30.0f, //titlebar_height
19
20=== modified file 'playground/demo-shell/demo_compositor.h'
21--- playground/demo-shell/demo_compositor.h 2014-12-08 04:03:47 +0000
22+++ playground/demo-shell/demo_compositor.h 2015-01-08 03:41:50 +0000
23@@ -47,7 +47,6 @@
24 public:
25 DemoCompositor(
26 graphics::DisplayBuffer& display_buffer,
27- graphics::GLProgramFactory const& factory,
28 std::shared_ptr<compositor::CompositorReport> const& report);
29 ~DemoCompositor();
30
31
32=== modified file 'playground/demo-shell/demo_renderer.cpp'
33--- playground/demo-shell/demo_renderer.cpp 2014-12-08 04:03:47 +0000
34+++ playground/demo-shell/demo_renderer.cpp 2015-01-08 03:41:50 +0000
35@@ -146,12 +146,11 @@
36 } // namespace
37
38 DemoRenderer::DemoRenderer(
39- graphics::GLProgramFactory const& program_factory,
40 Rectangle const& display_area,
41 compositor::DestinationAlpha dest_alpha,
42 float const titlebar_height,
43 float const shadow_radius) :
44- GLRenderer(program_factory,
45+ GLRenderer(
46 std::unique_ptr<graphics::GLTextureCache>(new compositor::RecentlyUsedCache()),
47 display_area,
48 dest_alpha),
49
50=== modified file 'playground/demo-shell/demo_renderer.h'
51--- playground/demo-shell/demo_renderer.h 2014-12-08 04:03:47 +0000
52+++ playground/demo-shell/demo_renderer.h 2015-01-08 03:41:50 +0000
53@@ -32,7 +32,6 @@
54 {
55 public:
56 DemoRenderer(
57- graphics::GLProgramFactory const& factory,
58 geometry::Rectangle const& display_area,
59 compositor::DestinationAlpha dest_alpha,
60 float const titlebar_height,
61
62=== modified file 'playground/demo-shell/demo_shell.cpp'
63--- playground/demo-shell/demo_shell.cpp 2014-12-19 02:31:34 +0000
64+++ playground/demo-shell/demo_shell.cpp 2015-01-08 03:41:50 +0000
65@@ -53,9 +53,7 @@
66 {
67 public:
68 DisplayBufferCompositorFactory(
69- std::shared_ptr<mg::GLProgramFactory> const& gl_program_factory,
70 std::shared_ptr<mc::CompositorReport> const& report) :
71- gl_program_factory(gl_program_factory),
72 report(report)
73 {
74 }
75@@ -64,11 +62,10 @@
76 mg::DisplayBuffer& display_buffer) override
77 {
78 return std::unique_ptr<mc::DisplayBufferCompositor>(
79- new me::DemoCompositor{display_buffer, *gl_program_factory, report});
80+ new me::DemoCompositor{display_buffer, report});
81 }
82
83 private:
84- std::shared_ptr<mg::GLProgramFactory> const gl_program_factory;
85 std::shared_ptr<mc::CompositorReport> const report;
86 };
87
88@@ -99,7 +96,6 @@
89 [this]()
90 {
91 return std::make_shared<me::DisplayBufferCompositorFactory>(
92- the_gl_program_factory(),
93 the_compositor_report());
94 });
95 }
96
97=== added file 'src/include/server/mir/compositor/gl_program_family.h'
98--- src/include/server/mir/compositor/gl_program_family.h 1970-01-01 00:00:00 +0000
99+++ src/include/server/mir/compositor/gl_program_family.h 2015-01-08 03:41:50 +0000
100@@ -0,0 +1,67 @@
101+/*
102+ * Copyright © 2015 Canonical Ltd.
103+ *
104+ * This program is free software: you can redistribute it and/or modify it
105+ * under the terms of the GNU General Public License version 3,
106+ * as published by the Free Software Foundation.
107+ *
108+ * This program is distributed in the hope that it will be useful,
109+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
110+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
111+ * GNU General Public License for more details.
112+ *
113+ * You should have received a copy of the GNU General Public License
114+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
115+ *
116+ * Authored by: Daniel van Vugt <daniel.van.vugt@canonical.com>
117+ */
118+
119+#ifndef MIR_COMPOSITOR_GL_PROGRAM_FAMILY_H_
120+#define MIR_COMPOSITOR_GL_PROGRAM_FAMILY_H_
121+
122+#include <GLES2/gl2.h>
123+#include <utility>
124+#include <map>
125+#include <unordered_map>
126+
127+namespace mir { namespace compositor {
128+
129+/**
130+ * GLProgramFamily represents a set of GLSL programs that are closely
131+ * related. Programs which point to the same shader source strings will be
132+ * made to share the same compiled shader objects.
133+ * A secondary intention is that this class may be extended to allow the
134+ * different programs within the family to share common patterns of uniform
135+ * usage too.
136+ */
137+class GLProgramFamily
138+{
139+public:
140+ GLProgramFamily() = default;
141+ GLProgramFamily(GLProgramFamily const&) = delete;
142+ GLProgramFamily& operator=(GLProgramFamily const&) = delete;
143+ ~GLProgramFamily() noexcept;
144+
145+ GLuint add_program(const GLchar* const static_vshader_src,
146+ const GLchar* const static_fshader_src);
147+
148+private:
149+ struct Shader
150+ {
151+ GLuint id = 0;
152+ void init(GLenum type, const GLchar* src);
153+ };
154+ typedef std::unordered_map<const GLchar*, Shader> ShaderMap;
155+ ShaderMap vshader, fshader;
156+
157+ typedef std::pair<GLuint, GLuint> ShaderPair;
158+ struct Program
159+ {
160+ GLuint id = 0;
161+ };
162+ std::map<ShaderPair, Program> program;
163+};
164+
165+}} // namespace mir::compositor
166+
167+#endif // MIR_COMPOSITOR_GL_PROGRAM_FAMILY_H_
168
169=== modified file 'src/include/server/mir/compositor/gl_renderer.h'
170--- src/include/server/mir/compositor/gl_renderer.h 2014-12-08 04:03:47 +0000
171+++ src/include/server/mir/compositor/gl_renderer.h 2015-01-08 03:41:50 +0000
172@@ -19,13 +19,12 @@
173 #ifndef MIR_COMPOSITOR_GL_RENDERER_H_
174 #define MIR_COMPOSITOR_GL_RENDERER_H_
175
176+#include <mir/compositor/gl_program_family.h>
177 #include <mir/compositor/renderer.h>
178-#include <mir/graphics/gl_program.h>
179 #include <mir/geometry/rectangle.h>
180 #include <mir/graphics/buffer_id.h>
181 #include <mir/graphics/renderable.h>
182 #include <mir/graphics/gl_primitive.h>
183-#include <mir/graphics/gl_program_factory.h>
184 #include <mir/graphics/gl_texture_cache.h>
185 #include <GLES2/gl2.h>
186 #include <unordered_map>
187@@ -43,7 +42,6 @@
188 {
189 public:
190 GLRenderer(
191- graphics::GLProgramFactory const& program_factory,
192 std::unique_ptr<graphics::GLTextureCache> && texture_cache,
193 geometry::Rectangle const& display_area,
194 DestinationAlpha dest_alpha);
195@@ -82,15 +80,25 @@
196
197 GLfloat clear_color[4];
198
199+ GLProgramFamily family;
200+ struct Program
201+ {
202+ GLuint id = 0;
203+ GLint tex_uniform = -1;
204+ GLint position_attr = -1;
205+ GLint texcoord_attr = -1;
206+ GLint centre_uniform = -1;
207+ GLint display_transform_uniform = -1;
208+ GLint transform_uniform = -1;
209+ GLint screen_to_gl_coords_uniform = -1;
210+ GLint alpha_uniform = -1;
211+
212+ Program(GLuint program_id);
213+ };
214+ std::vector<Program> programs;
215+
216 private:
217- std::unique_ptr<graphics::GLProgram> program;
218 std::unique_ptr<graphics::GLTextureCache> mutable texture_cache;
219- GLuint position_attr_loc;
220- GLuint texcoord_attr_loc;
221- GLuint centre_uniform_loc;
222- GLuint display_transform_uniform_loc;
223- GLuint transform_uniform_loc;
224- GLuint alpha_uniform_loc;
225 float rotation;
226 DestinationAlpha const dest_alpha;
227 geometry::Rectangle viewport;
228
229=== modified file 'src/server/compositor/CMakeLists.txt'
230--- src/server/compositor/CMakeLists.txt 2014-12-08 04:03:47 +0000
231+++ src/server/compositor/CMakeLists.txt 2015-01-08 03:41:50 +0000
232@@ -8,6 +8,7 @@
233 buffer_stream_surfaces.cpp
234 gl_renderer.cpp
235 gl_renderer_factory.cpp
236+ gl_program_family.cpp
237 multi_threaded_compositor.cpp
238 occlusion.cpp
239 default_configuration.cpp
240
241=== modified file 'src/server/compositor/default_configuration.cpp'
242--- src/server/compositor/default_configuration.cpp 2014-12-11 02:43:01 +0000
243+++ src/server/compositor/default_configuration.cpp 2015-01-08 03:41:50 +0000
244@@ -95,7 +95,7 @@
245 return renderer_factory(
246 [this]()
247 {
248- return std::make_shared<mc::GLRendererFactory>(the_gl_program_factory());
249+ return std::make_shared<mc::GLRendererFactory>();
250 });
251 }
252
253
254=== added file 'src/server/compositor/gl_program_family.cpp'
255--- src/server/compositor/gl_program_family.cpp 1970-01-01 00:00:00 +0000
256+++ src/server/compositor/gl_program_family.cpp 2015-01-08 03:41:50 +0000
257@@ -0,0 +1,105 @@
258+/*
259+ * Copyright © 2015 Canonical Ltd.
260+ *
261+ * This program is free software: you can redistribute it and/or modify it
262+ * under the terms of the GNU General Public License version 3,
263+ * as published by the Free Software Foundation.
264+ *
265+ * This program is distributed in the hope that it will be useful,
266+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
267+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
268+ * GNU General Public License for more details.
269+ *
270+ * You should have received a copy of the GNU General Public License
271+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
272+ *
273+ * Authored by: Daniel van Vugt <daniel.van.vugt@canonical.com>
274+ */
275+
276+#include "mir/compositor/gl_program_family.h"
277+
278+namespace mir { namespace compositor {
279+
280+void GLProgramFamily::Shader::init(GLenum type, const GLchar* src)
281+{
282+ if (!id)
283+ {
284+ id = glCreateShader(type);
285+ if (id)
286+ {
287+ glShaderSource(id, 1, &src, NULL);
288+ glCompileShader(id);
289+ GLint ok;
290+ glGetShaderiv(id, GL_COMPILE_STATUS, &ok);
291+ if (!ok)
292+ {
293+ GLchar log[1024];
294+ glGetShaderInfoLog(id, sizeof log - 1, NULL, log);
295+ log[sizeof log - 1] = '\0';
296+ glDeleteShader(id);
297+ id = 0;
298+ throw std::runtime_error(std::string("Compile failed: ")+
299+ log + " for:\n" + src);
300+ }
301+ }
302+ }
303+}
304+
305+GLProgramFamily::~GLProgramFamily() noexcept
306+{
307+ // shader and program lifetimes are managed manually, so that we don't
308+ // need any reference counting or to worry about how many copy constructions
309+ // might have been followed by destructor calls during container resizes.
310+
311+ for (auto& p : program)
312+ {
313+ if (p.second.id)
314+ glDeleteProgram(p.second.id);
315+ }
316+
317+ for (auto& v : vshader)
318+ {
319+ if (v.second.id)
320+ glDeleteShader(v.second.id);
321+ }
322+
323+ for (auto& f : fshader)
324+ {
325+ if (f.second.id)
326+ glDeleteShader(f.second.id);
327+ }
328+}
329+
330+GLuint GLProgramFamily::add_program(const GLchar* const vshader_src,
331+ const GLchar* const fshader_src)
332+{
333+ auto& v = vshader[vshader_src];
334+ if (!v.id) v.init(GL_VERTEX_SHADER, vshader_src);
335+
336+ auto& f = fshader[fshader_src];
337+ if (!f.id) f.init(GL_FRAGMENT_SHADER, fshader_src);
338+
339+ auto& p = program[{v.id, f.id}];
340+ if (!p.id)
341+ {
342+ p.id = glCreateProgram();
343+ glAttachShader(p.id, v.id);
344+ glAttachShader(p.id, f.id);
345+ glLinkProgram(p.id);
346+ GLint ok;
347+ glGetProgramiv(p.id, GL_LINK_STATUS, &ok);
348+ if (!ok)
349+ {
350+ GLchar log[1024];
351+ glGetProgramInfoLog(p.id, sizeof log - 1, NULL, log);
352+ log[sizeof log - 1] = '\0';
353+ glDeleteShader(p.id);
354+ p.id = 0;
355+ throw std::runtime_error(std::string("Link failed: ")+log);
356+ }
357+ }
358+
359+ return p.id;
360+}
361+
362+}} // namespace mir::compositor
363
364=== modified file 'src/server/compositor/gl_renderer.cpp'
365--- src/server/compositor/gl_renderer.cpp 2014-12-09 03:15:24 +0000
366+++ src/server/compositor/gl_renderer.cpp 2015-01-08 03:41:50 +0000
367@@ -41,7 +41,13 @@
368 namespace
369 {
370
371-const GLchar* vertex_shader_src =
372+enum
373+{
374+ default_program_index = 0,
375+ alpha_program_index = 1
376+};
377+
378+const GLchar vshader[] =
379 {
380 "attribute vec3 position;\n"
381 "attribute vec2 texcoord;\n"
382@@ -58,7 +64,7 @@
383 "}\n"
384 };
385
386-const GLchar* fragment_shader_src =
387+const GLchar alpha_fshader[] =
388 {
389 "precision mediump float;\n"
390 "uniform sampler2D tex;\n"
391@@ -69,21 +75,40 @@
392 " gl_FragColor = alpha*frag;\n"
393 "}\n"
394 };
395+
396+const GLchar default_fshader[] = // Should be faster than blending in theory
397+{
398+ "precision mediump float;\n"
399+ "uniform sampler2D tex;\n"
400+ "varying vec2 v_texcoord;\n"
401+ "void main() {\n"
402+ " gl_FragColor = texture2D(tex, v_texcoord);\n"
403+ "}\n"
404+};
405+
406+}
407+
408+mc::GLRenderer::Program::Program(GLuint program_id)
409+{
410+ id = program_id;
411+ position_attr = glGetAttribLocation(id, "position");
412+ texcoord_attr = glGetAttribLocation(id, "texcoord");
413+ tex_uniform = glGetUniformLocation(id, "tex");
414+ centre_uniform = glGetUniformLocation(id, "centre");
415+ display_transform_uniform = glGetUniformLocation(id, "display_transform");
416+ transform_uniform = glGetUniformLocation(id, "transform");
417+ screen_to_gl_coords_uniform = glGetUniformLocation(id, "screen_to_gl_coords");
418+ alpha_uniform = glGetUniformLocation(id, "alpha");
419 }
420
421 mc::GLRenderer::GLRenderer(
422- mg::GLProgramFactory const& program_factory,
423 std::unique_ptr<mg::GLTextureCache> && texture_cache,
424 geom::Rectangle const& display_area,
425 DestinationAlpha dest_alpha)
426 : clear_color{0.0f, 0.0f, 0.0f, 1.0f},
427- program(program_factory.create_gl_program(vertex_shader_src, fragment_shader_src)),
428+ programs{family.add_program(vshader, default_fshader),
429+ family.add_program(vshader, alpha_fshader)},
430 texture_cache(std::move(texture_cache)),
431- position_attr_loc(0),
432- texcoord_attr_loc(0),
433- centre_uniform_loc(0),
434- transform_uniform_loc(0),
435- alpha_uniform_loc(0),
436 rotation(NAN), // ensure the first set_rotation succeeds
437 dest_alpha(dest_alpha)
438 {
439@@ -101,19 +126,12 @@
440 if (!val) val = "";
441 mir::log_info("%s: %s", s.label, val);
442 }
443-
444- glUseProgram(*program);
445-
446- /* Set up program variables */
447- GLint tex_loc = glGetUniformLocation(*program, "tex");
448- display_transform_uniform_loc = glGetUniformLocation(*program, "display_transform");
449- transform_uniform_loc = glGetUniformLocation(*program, "transform");
450- alpha_uniform_loc = glGetUniformLocation(*program, "alpha");
451- position_attr_loc = glGetAttribLocation(*program, "position");
452- texcoord_attr_loc = glGetAttribLocation(*program, "texcoord");
453- centre_uniform_loc = glGetUniformLocation(*program, "centre");
454-
455- glUniform1i(tex_loc, 0);
456+
457+ for (auto& p : programs)
458+ {
459+ glUseProgram(p.id);
460+ glUniform1i(p.tex_uniform, 0);
461+ }
462
463 glBindBuffer(GL_ARRAY_BUFFER, 0);
464 glUseProgram(0);
465@@ -149,10 +167,15 @@
466
467 void mc::GLRenderer::render(mg::Renderable const& renderable) const
468 {
469-
470- glUseProgram(*program);
471-
472- if (renderable.shaped() || renderable.alpha() < 1.0f)
473+ const Program* prog = &programs[default_program_index];
474+
475+ if (renderable.alpha() < 1.0f)
476+ {
477+ prog = &programs[alpha_program_index];
478+ glEnable(GL_BLEND);
479+ glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
480+ }
481+ else if (renderable.shaped())
482 {
483 glEnable(GL_BLEND);
484 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
485@@ -161,6 +184,8 @@
486 {
487 glDisable(GL_BLEND);
488 }
489+
490+ glUseProgram(prog->id);
491 glActiveTexture(GL_TEXTURE0);
492
493 auto const& rect = renderable.screen_position();
494@@ -168,15 +193,17 @@
495 rect.size.width.as_int() / 2.0f;
496 GLfloat centrey = rect.top_left.y.as_int() +
497 rect.size.height.as_int() / 2.0f;
498- glUniform2f(centre_uniform_loc, centrex, centrey);
499+ glUniform2f(prog->centre_uniform, centrex, centrey);
500
501- glUniformMatrix4fv(transform_uniform_loc, 1, GL_FALSE,
502+ glUniformMatrix4fv(prog->transform_uniform, 1, GL_FALSE,
503 glm::value_ptr(renderable.transformation()));
504- glUniform1f(alpha_uniform_loc, renderable.alpha());
505+
506+ if (prog->alpha_uniform >= 0)
507+ glUniform1f(prog->alpha_uniform, renderable.alpha());
508
509 /* Draw */
510- glEnableVertexAttribArray(position_attr_loc);
511- glEnableVertexAttribArray(texcoord_attr_loc);
512+ glEnableVertexAttribArray(prog->position_attr);
513+ glEnableVertexAttribArray(prog->texcoord_attr);
514
515 primitives.clear();
516 tessellate(primitives, renderable);
517@@ -193,18 +220,18 @@
518 else
519 surface_tex->bind();
520
521- glVertexAttribPointer(position_attr_loc, 3, GL_FLOAT,
522+ glVertexAttribPointer(prog->position_attr, 3, GL_FLOAT,
523 GL_FALSE, sizeof(mg::GLVertex),
524 &p.vertices[0].position);
525- glVertexAttribPointer(texcoord_attr_loc, 2, GL_FLOAT,
526+ glVertexAttribPointer(prog->texcoord_attr, 2, GL_FLOAT,
527 GL_FALSE, sizeof(mg::GLVertex),
528 &p.vertices[0].texcoord);
529
530 glDrawArrays(p.type, 0, p.nvertices);
531 }
532
533- glDisableVertexAttribArray(texcoord_attr_loc);
534- glDisableVertexAttribArray(position_attr_loc);
535+ glDisableVertexAttribArray(prog->texcoord_attr);
536+ glDisableVertexAttribArray(prog->position_attr);
537 }
538
539 void mc::GLRenderer::set_viewport(geometry::Rectangle const& rect)
540@@ -243,9 +270,12 @@
541 -rect.top_left.y.as_float(),
542 0.0f});
543
544- glUseProgram(*program);
545- GLint mat_loc = glGetUniformLocation(*program, "screen_to_gl_coords");
546- glUniformMatrix4fv(mat_loc, 1, GL_FALSE, glm::value_ptr(screen_to_gl_coords));
547+ for (auto& p : programs)
548+ {
549+ glUseProgram(p.id);
550+ glUniformMatrix4fv(p.screen_to_gl_coords_uniform, 1, GL_FALSE,
551+ glm::value_ptr(screen_to_gl_coords));
552+ }
553 glUseProgram(0);
554
555 viewport = rect;
556@@ -263,8 +293,12 @@
557 -sin, cos, 0.0f, 0.0f,
558 0.0f, 0.0f, 1.0f, 0.0f,
559 0.0f, 0.0f, 0.0f, 1.0f};
560- glUseProgram(*program);
561- glUniformMatrix4fv(display_transform_uniform_loc, 1, GL_FALSE, rot);
562+
563+ for (auto& p : programs)
564+ {
565+ glUseProgram(p.id);
566+ glUniformMatrix4fv(p.display_transform_uniform, 1, GL_FALSE, rot);
567+ }
568 glUseProgram(0);
569
570 rotation = degrees;
571
572=== modified file 'src/server/compositor/gl_renderer_factory.cpp'
573--- src/server/compositor/gl_renderer_factory.cpp 2014-12-08 04:03:47 +0000
574+++ src/server/compositor/gl_renderer_factory.cpp 2015-01-08 03:41:50 +0000
575@@ -26,16 +26,11 @@
576 namespace mc = mir::compositor;
577 namespace geom = mir::geometry;
578
579-mc::GLRendererFactory::GLRendererFactory(std::shared_ptr<mg::GLProgramFactory> const& factory) :
580- program_factory(factory)
581-{
582-}
583-
584 std::unique_ptr<mc::Renderer>
585 mc::GLRendererFactory::create_renderer_for(geom::Rectangle const& rect,
586 DestinationAlpha dest_alpha)
587 {
588- auto raw = new GLRenderer(*program_factory,
589+ auto raw = new GLRenderer(
590 std::unique_ptr<mg::GLTextureCache>(new RecentlyUsedCache()),
591 rect, dest_alpha);
592 return std::unique_ptr<mc::Renderer>(raw);
593
594=== modified file 'src/server/compositor/gl_renderer_factory.h'
595--- src/server/compositor/gl_renderer_factory.h 2014-12-08 04:03:47 +0000
596+++ src/server/compositor/gl_renderer_factory.h 2015-01-08 03:41:50 +0000
597@@ -23,21 +23,14 @@
598
599 namespace mir
600 {
601-namespace graphics
602-{
603-class GLProgramFactory;
604-}
605 namespace compositor
606 {
607
608 class GLRendererFactory : public RendererFactory
609 {
610 public:
611- GLRendererFactory(std::shared_ptr<graphics::GLProgramFactory> const& factory);
612 std::unique_ptr<Renderer> create_renderer_for(geometry::Rectangle const& rect,
613 DestinationAlpha dest_alpha);
614-private:
615- std::shared_ptr<graphics::GLProgramFactory> const program_factory;
616 };
617 }
618 }
619
620=== modified file 'src/server/symbols.map'
621--- src/server/symbols.map 2014-12-19 02:31:34 +0000
622+++ src/server/symbols.map 2015-01-08 03:41:50 +0000
623@@ -787,6 +787,7 @@
624 mir::compositor::GLRenderer::set_viewport*;
625 mir::compositor::GLRenderer::suspend*;
626 mir::compositor::GLRenderer::tessellate*;
627+ mir::compositor::GLProgramFamily::*;
628 typeinfo?for?mir::compositor::GLRenderer;
629 vtable?for?mir::compositor::GLRenderer;
630 vtable?for?mir::compositor::RecentlyUsedCache;
631
632=== modified file 'tests/unit-tests/compositor/test_gl_renderer.cpp'
633--- tests/unit-tests/compositor/test_gl_renderer.cpp 2014-12-08 04:03:47 +0000
634+++ tests/unit-tests/compositor/test_gl_renderer.cpp 2015-01-08 03:41:50 +0000
635@@ -27,7 +27,6 @@
636 #include <mir/graphics/gl_texture.h>
637 #include <mir/compositor/gl_renderer.h>
638 #include <mir/compositor/destination_alpha.h>
639-#include "src/server/graphics/program_factory.h"
640 #include <mir_test/fake_shared.h>
641 #include <mir_test_doubles/mock_buffer.h>
642 #include <mir_test_doubles/mock_renderable.h>
643@@ -82,22 +81,23 @@
644 void SetUpMockProgramData(mtd::MockGL &mock_gl)
645 {
646 /* Uniforms and Attributes */
647- EXPECT_CALL(mock_gl, glUseProgram(stub_program));
648+ ON_CALL(mock_gl, glGetAttribLocation(stub_program, "position"))
649+ .WillByDefault(Return(position_attr_location));
650+ ON_CALL(mock_gl, glGetAttribLocation(stub_program, "texcoord"))
651+ .WillByDefault(Return(texcoord_attr_location));
652
653- EXPECT_CALL(mock_gl, glGetUniformLocation(stub_program, _))
654- .WillOnce(Return(tex_uniform_location));
655- EXPECT_CALL(mock_gl, glGetUniformLocation(stub_program, _))
656- .WillOnce(Return(display_transform_uniform_location));
657- EXPECT_CALL(mock_gl, glGetUniformLocation(stub_program, _))
658- .WillOnce(Return(transform_uniform_location));
659- EXPECT_CALL(mock_gl, glGetUniformLocation(stub_program, _))
660- .WillOnce(Return(alpha_uniform_location));
661- EXPECT_CALL(mock_gl, glGetAttribLocation(stub_program, _))
662- .WillOnce(Return(position_attr_location));
663- EXPECT_CALL(mock_gl, glGetAttribLocation(stub_program, _))
664- .WillOnce(Return(texcoord_attr_location));
665- EXPECT_CALL(mock_gl, glGetUniformLocation(stub_program, _))
666- .WillOnce(Return(centre_uniform_location));
667+ ON_CALL(mock_gl, glGetUniformLocation(stub_program, "tex"))
668+ .WillByDefault(Return(tex_uniform_location));
669+ ON_CALL(mock_gl, glGetUniformLocation(stub_program, "centre"))
670+ .WillByDefault(Return(centre_uniform_location));
671+ ON_CALL(mock_gl, glGetUniformLocation(stub_program, "display_transform"))
672+ .WillByDefault(Return(display_transform_uniform_location));
673+ ON_CALL(mock_gl, glGetUniformLocation(stub_program, "transform"))
674+ .WillByDefault(Return(transform_uniform_location));
675+ ON_CALL(mock_gl, glGetUniformLocation(stub_program, "screen_to_gl_coords"))
676+ .WillByDefault(Return(screen_to_gl_coords_uniform_location));
677+ ON_CALL(mock_gl, glGetUniformLocation(stub_program, "alpha"))
678+ .WillByDefault(Return(alpha_uniform_location));
679 }
680
681 class GLRenderer :
682@@ -152,16 +152,14 @@
683
684 InSequence s;
685 SetUpMockProgramData(mock_gl);
686- EXPECT_CALL(mock_gl, glUniform1i(tex_uniform_location, 0));
687
688 EXPECT_CALL(mock_gl, glGetUniformLocation(stub_program, _))
689- .WillOnce(Return(screen_to_gl_coords_uniform_location));
690+ .WillRepeatedly(Return(screen_to_gl_coords_uniform_location));
691
692 display_area = {{1, 2}, {3, 4}};
693 mock_texture_cache.reset(new testing::NiceMock<MockGLTextureCache>());
694 }
695
696- mg::ProgramFactory program_factory;
697 std::unique_ptr<MockGLTextureCache> mock_texture_cache;
698 testing::NiceMock<mtd::MockGL> mock_gl;
699 std::shared_ptr<mtd::MockBuffer> mock_buffer;
700@@ -173,46 +171,11 @@
701
702 }
703
704-TEST_F(GLRenderer, render_is_done_in_sequence)
705-{
706- InSequence seq;
707-
708- EXPECT_CALL(mock_gl, glClearColor(_, _, _, _));
709- EXPECT_CALL(mock_gl, glClear(_));
710- EXPECT_CALL(mock_gl, glUseProgram(stub_program));
711- EXPECT_CALL(*renderable, shaped())
712- .WillOnce(Return(true));
713- EXPECT_CALL(mock_gl, glEnable(GL_BLEND));
714- EXPECT_CALL(mock_gl, glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA));
715- EXPECT_CALL(mock_gl, glActiveTexture(GL_TEXTURE0));
716-
717- EXPECT_CALL(mock_gl, glUniform2f(centre_uniform_location, _, _));
718- EXPECT_CALL(*renderable, transformation())
719- .WillOnce(Return(trans));
720- EXPECT_CALL(mock_gl, glUniformMatrix4fv(transform_uniform_location, 1, GL_FALSE, _));
721- EXPECT_CALL(*renderable, alpha())
722- .WillOnce(Return(0.0f));
723- EXPECT_CALL(mock_gl, glUniform1f(alpha_uniform_location, _));
724-
725- EXPECT_CALL(mock_gl, glEnableVertexAttribArray(position_attr_location));
726- EXPECT_CALL(mock_gl, glEnableVertexAttribArray(texcoord_attr_location));
727- EXPECT_CALL(*mock_texture_cache, load(_));
728-
729- EXPECT_CALL(mock_gl, glVertexAttribPointer(position_attr_location, 3,
730- GL_FLOAT, GL_FALSE, _, _));
731- EXPECT_CALL(mock_gl, glVertexAttribPointer(texcoord_attr_location, 2,
732- GL_FLOAT, GL_FALSE, _, _));
733-
734- EXPECT_CALL(mock_gl, glDrawArrays(GL_TRIANGLE_STRIP, 0, 4));
735-
736- EXPECT_CALL(mock_gl, glDisableVertexAttribArray(texcoord_attr_location));
737- EXPECT_CALL(mock_gl, glDisableVertexAttribArray(position_attr_location));
738-
739- EXPECT_CALL(*mock_texture_cache, drop_unused());
740-
741- mc::GLRenderer renderer(program_factory, std::move(mock_texture_cache), display_area, mc::DestinationAlpha::opaque);
742- renderer.render(renderable_list);
743-}
744+/*
745+ * Once stood here: TEST_F(GLRenderer, render_is_done_in_sequence)
746+ * but it was a useless test that protected against nothing, and was
747+ * painful to maintain. So it has been deleted.
748+ */
749
750 TEST_F(GLRenderer, disables_blending_for_rgbx_surfaces)
751 {
752@@ -221,7 +184,7 @@
753 .WillOnce(Return(false));
754 EXPECT_CALL(mock_gl, glDisable(GL_BLEND));
755
756- mc::GLRenderer renderer(program_factory, std::move(mock_texture_cache), display_area, mc::DestinationAlpha::opaque);
757+ mc::GLRenderer renderer(std::move(mock_texture_cache), display_area, mc::DestinationAlpha::opaque);
758 renderer.render(renderable_list);
759 }
760
761@@ -231,10 +194,9 @@
762 struct OverriddenTessellateRenderer : public mc::GLRenderer
763 {
764 OverriddenTessellateRenderer(
765- mg::GLProgramFactory const& program_factory,
766 std::unique_ptr<mg::GLTextureCache> && texture_cache,
767 mir::geometry::Rectangle const& display_area, unsigned int num_primitives) :
768- GLRenderer(program_factory, std::move(texture_cache), display_area, mc::DestinationAlpha::opaque),
769+ GLRenderer(std::move(texture_cache), display_area, mc::DestinationAlpha::opaque),
770 num_primitives(num_primitives)
771 {
772 }
773@@ -258,7 +220,7 @@
774 EXPECT_CALL(mock_gl, glBindTexture(GL_TEXTURE_2D, _))
775 .Times(bind_count);
776
777- OverriddenTessellateRenderer renderer(program_factory, std::move(mock_texture_cache), display_area, bind_count);
778+ OverriddenTessellateRenderer renderer(std::move(mock_texture_cache), display_area, bind_count);
779 renderer.render(renderable_list);
780 }
781
782@@ -270,7 +232,7 @@
783 EXPECT_CALL(mock_gl, glClear(_));
784 EXPECT_CALL(mock_gl, glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE));
785
786- mc::GLRenderer renderer(program_factory, std::move(mock_texture_cache), display_area,
787+ mc::GLRenderer renderer(std::move(mock_texture_cache), display_area,
788 mc::DestinationAlpha::opaque);
789
790 renderer.render(renderable_list);
791@@ -280,7 +242,7 @@
792 {
793 EXPECT_CALL(mock_gl, glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
794
795- mc::GLRenderer renderer(program_factory, std::move(mock_texture_cache), display_area,
796+ mc::GLRenderer renderer(std::move(mock_texture_cache), display_area,
797 mc::DestinationAlpha::generate_from_source);
798
799 renderer.render(renderable_list);
800
801=== modified file 'tests/unit-tests/examples/test_demo_compositor.cpp'
802--- tests/unit-tests/examples/test_demo_compositor.cpp 2014-12-08 04:03:47 +0000
803+++ tests/unit-tests/examples/test_demo_compositor.cpp 2015-01-08 03:41:50 +0000
804@@ -27,7 +27,6 @@
805
806 #include "mir_test_doubles/mock_gl.h"
807 #include "mir_test_doubles/stub_display_buffer.h"
808-#include "mir_test_doubles/stub_gl_program_factory.h"
809 #include "mir_test_doubles/stub_buffer_stream.h"
810 #include "mir_test_doubles/stub_renderable.h"
811 #include "mir_test_doubles/null_surface_configurator.h"
812@@ -65,7 +64,6 @@
813 testing::NiceMock<mtd::MockGL> mock_gl;
814 mtd::StubDisplayBuffer stub_display_buffer{
815 geom::Rectangle{{0,0}, {1000,1000}}};
816- mtd::StubGLProgramFactory stub_factory;
817 ms::BasicSurface stub_surface{
818 std::string("stub"),
819 geom::Rectangle{{0,0},{100,100}},
820@@ -77,13 +75,21 @@
821 std::shared_ptr<mir::graphics::CursorImage>(),
822 mir::report::null_scene_report()};
823
824- me::DemoCompositor demo_compositor{
825- stub_display_buffer,
826- stub_factory,
827- mir::report::null_compositor_report()};
828-
829 testing::NiceMock<MockSceneElement> element;
830 mc::SceneElementSequence scene_elements{mt::fake_shared(element)};
831+
832+ void SetUp()
833+ {
834+ using namespace testing;
835+ ON_CALL(mock_gl, glCreateShader(_))
836+ .WillByDefault(Return(12));
837+ ON_CALL(mock_gl, glCreateProgram())
838+ .WillByDefault(Return(34));
839+ ON_CALL(mock_gl, glGetShaderiv(_, _, _))
840+ .WillByDefault(SetArgPointee<2>(GL_TRUE));
841+ ON_CALL(mock_gl, glGetProgramiv(_, _, _))
842+ .WillByDefault(SetArgPointee<2>(GL_TRUE));
843+ }
844 };
845
846 }
847@@ -93,6 +99,10 @@
848 {
849 using namespace testing;
850
851+ me::DemoCompositor demo_compositor{
852+ stub_display_buffer,
853+ mir::report::null_compositor_report()};
854+
855 EXPECT_CALL(element, renderable())
856 .Times(2)
857 .WillOnce(Return(std::make_shared<mtd::StubRenderable>(true)))
858
859=== modified file 'tests/unit-tests/examples/test_demo_renderer.cpp'
860--- tests/unit-tests/examples/test_demo_renderer.cpp 2014-12-08 04:03:47 +0000
861+++ tests/unit-tests/examples/test_demo_renderer.cpp 2015-01-08 03:41:50 +0000
862@@ -19,7 +19,6 @@
863 #include "mir/graphics/renderable.h"
864 #include "mir/compositor/destination_alpha.h"
865 #include "mir_test_doubles/fake_renderable.h"
866-#include "mir_test_doubles/stub_gl_program_factory.h"
867 #include "mir_test_doubles/mock_gl.h"
868 #include "playground/demo-shell/demo_renderer.h"
869 #include <gtest/gtest.h>
870@@ -32,16 +31,28 @@
871 struct DemoRenderer : public testing::Test
872 {
873 testing::NiceMock<mtd::MockGL> mock_gl;
874- mtd::StubGLProgramFactory stub_factory;
875 geom::Rectangle region{{0, 0}, {100, 100}};
876 mc::DestinationAlpha dest_alpha{mc::DestinationAlpha::opaque};
877 int const shadow_radius{20};
878 int const titlebar_height{5};
879+
880+ void SetUp()
881+ {
882+ using namespace testing;
883+ ON_CALL(mock_gl, glCreateShader(_))
884+ .WillByDefault(Return(12));
885+ ON_CALL(mock_gl, glCreateProgram())
886+ .WillByDefault(Return(34));
887+ ON_CALL(mock_gl, glGetShaderiv(_, _, _))
888+ .WillByDefault(SetArgPointee<2>(GL_TRUE));
889+ ON_CALL(mock_gl, glGetProgramiv(_, _, _))
890+ .WillByDefault(SetArgPointee<2>(GL_TRUE));
891+ }
892 };
893
894 TEST_F(DemoRenderer, detects_embellishments_on_renderables)
895 {
896- me::DemoRenderer demo_renderer(stub_factory, region, dest_alpha, titlebar_height, shadow_radius);
897+ me::DemoRenderer demo_renderer(region, dest_alpha, titlebar_height, shadow_radius);
898
899 mtd::FakeRenderable fullscreen_surface(region);
900 mtd::FakeRenderable oversized_surface(geom::Rectangle{{-10, -10}, {120, 120}});
901
902=== modified file 'tests/unit-tests/graphics/test_program_factory.cpp'
903--- tests/unit-tests/graphics/test_program_factory.cpp 2014-12-08 04:03:47 +0000
904+++ tests/unit-tests/graphics/test_program_factory.cpp 2015-01-08 03:41:50 +0000
905@@ -24,9 +24,7 @@
906 #include <gtest/gtest.h>
907 #include <gmock/gmock.h>
908 #include <mir/geometry/rectangle.h>
909-#include <mir/compositor/renderer.h>
910 #include <mir/compositor/destination_alpha.h>
911-#include "src/server/compositor/gl_renderer_factory.h"
912 #include "src/server/graphics/program_factory.h"
913 #include <mir_test/fake_shared.h>
914 #include <mir_test_doubles/mock_buffer.h>
915@@ -67,26 +65,22 @@
916 void ExpectShaderCompileSuccess(const GLint shader, mtd::MockGL &mock_gl)
917 {
918 EXPECT_CALL(mock_gl, glGetShaderiv(shader, GL_COMPILE_STATUS, _))
919- .WillOnce(SetArgPointee<2>(GL_TRUE));
920+ .WillRepeatedly(SetArgPointee<2>(GL_TRUE));
921 }
922
923 void SetUpMockVertexShader(mtd::MockGL &mock_gl, const std::function<void(const GLint, mtd::MockGL &)> &shader_compile_expectation)
924 {
925 /* Vertex Shader */
926- EXPECT_CALL(mock_gl, glCreateShader(GL_VERTEX_SHADER))
927- .WillOnce(Return(stub_v_shader));
928- EXPECT_CALL(mock_gl, glShaderSource(stub_v_shader, 1, _, 0));
929- EXPECT_CALL(mock_gl, glCompileShader(stub_v_shader));
930+ ON_CALL(mock_gl, glCreateShader(GL_VERTEX_SHADER))
931+ .WillByDefault(Return(stub_v_shader));
932 shader_compile_expectation(stub_v_shader, mock_gl);
933 }
934
935 void SetUpMockFragmentShader(mtd::MockGL &mock_gl, const std::function<void(const GLint, mtd::MockGL &)> &shader_compile_expectation)
936 {
937 /* Fragment Shader */
938- EXPECT_CALL(mock_gl, glCreateShader(GL_FRAGMENT_SHADER))
939- .WillOnce(Return(stub_f_shader));
940- EXPECT_CALL(mock_gl, glShaderSource(stub_f_shader, 1, _, 0));
941- EXPECT_CALL(mock_gl, glCompileShader(stub_f_shader));
942+ ON_CALL(mock_gl, glCreateShader(GL_FRAGMENT_SHADER))
943+ .WillByDefault(Return(stub_f_shader));
944 shader_compile_expectation(stub_f_shader, mock_gl);
945 }
946
947@@ -99,30 +93,22 @@
948 void ExpectProgramLinkSuccess(const GLint program, mtd::MockGL &mock_gl)
949 {
950 EXPECT_CALL(mock_gl, glGetProgramiv(program, GL_LINK_STATUS, _))
951- .WillOnce(SetArgPointee<2>(GL_TRUE));
952+ .WillRepeatedly(SetArgPointee<2>(GL_TRUE));
953 }
954
955 void SetUpMockGraphicsProgram(mtd::MockGL &mock_gl, const std::function<void(const GLint, mtd::MockGL &)> &program_link_expectation)
956 {
957 /* Graphics Program */
958- EXPECT_CALL(mock_gl, glCreateProgram())
959- .WillOnce(Return(stub_program));
960- EXPECT_CALL(mock_gl, glAttachShader(stub_program, stub_v_shader));
961- EXPECT_CALL(mock_gl, glAttachShader(stub_program, stub_f_shader));
962- EXPECT_CALL(mock_gl, glLinkProgram(stub_program));
963+ ON_CALL(mock_gl, glCreateProgram())
964+ .WillByDefault(Return(stub_program));
965 program_link_expectation(stub_program, mock_gl);
966 }
967
968 class ProgramFactory : public testing::Test
969 {
970 public:
971- ProgramFactory() :
972- gl_renderer_factory{std::make_shared<mg::ProgramFactory>()}
973- {
974- }
975 testing::NiceMock<mtd::MockGL> mock_gl;
976- mc::GLRendererFactory gl_renderer_factory;
977- mir::geometry::Rectangle display_area;
978+ mg::ProgramFactory factory;
979 };
980
981 ACTION_P2(CopyString, str, len)
982@@ -152,7 +138,7 @@
983 stub_info_log.size()));
984
985 EXPECT_THROW({
986- auto r = gl_renderer_factory.create_renderer_for(display_area, mc::DestinationAlpha::opaque);
987+ auto p = factory.create_gl_program("foo", "bar");
988 }, std::runtime_error);
989 }
990
991@@ -173,7 +159,7 @@
992 stub_info_log.size()));
993
994 EXPECT_THROW({
995- auto r = gl_renderer_factory.create_renderer_for(display_area, mc::DestinationAlpha::opaque);
996+ auto p = factory.create_gl_program("foo", "bar");
997 }, std::runtime_error);
998 }
999
1000@@ -195,7 +181,7 @@
1001 stub_info_log.size()));
1002
1003 EXPECT_THROW({
1004- auto r = gl_renderer_factory.create_renderer_for(display_area, mc::DestinationAlpha::opaque);
1005+ auto p = factory.create_gl_program("foo", "bar");
1006 }, std::runtime_error);
1007 }
1008
1009@@ -207,6 +193,6 @@
1010 SetUpMockFragmentShader(mock_gl, std::bind(ExpectShaderCompileSuccess, _1, _2));
1011 SetUpMockGraphicsProgram(mock_gl, std::bind(ExpectProgramLinkSuccess, _1, _2));
1012
1013- gl_renderer_factory.create_renderer_for(display_area, mc::DestinationAlpha::opaque);
1014+ auto p = factory.create_gl_program("foo", "bar");
1015 }
1016 }

Subscribers

People subscribed via source and target branches