Merge lp:~vanvugt/mir/fix-1350674 into lp:mir
- fix-1350674
- Merge into development-branch
Status: | Merged |
---|---|
Approved by: | Daniel van Vugt |
Approved revision: | no longer in the source branch. |
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 |
Related bugs: |
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.
Description of the change
PS Jenkins bot (ps-jenkins) wrote : | # |
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:2207
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
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.
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.
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.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:2210
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
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).
Robert Carr (robertcarr) wrote : | # |
GLProgramCache would have avoided the concern yes.
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 +GLProgramFamil
297 +{
298 +}
why not use default constructor?
137 + GLuint add_program(const char* vshader, const char* fshader);
string?
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...
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.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:2215
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Autolanding.
More details in the following jenkins job:
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
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
Daniel van Vugt (vanvugt) wrote : | # |
Robert: I already changed it to the syntax you want some hours before your comment :)
Daniel van Vugt (vanvugt) wrote : | # |
All "Needs Fixings" resolved, or explained.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:2216
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Robert Carr (robertcarr) : | # |
Preview Diff
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 | } |
PASSED: Continuous integration, rev:2206 jenkins. qa.ubuntu. com/job/ mir-ci/ 2556/ jenkins. qa.ubuntu. com/job/ mir-android- vivid-i386- build/703 jenkins. qa.ubuntu. com/job/ mir-clang- vivid-amd64- build/703 jenkins. qa.ubuntu. com/job/ mir-mediumtests -vivid- touch/677 jenkins. qa.ubuntu. com/job/ mir-vivid- amd64-ci/ 553 jenkins. qa.ubuntu. com/job/ mir-vivid- amd64-ci/ 553/artifact/ work/output/ *zip*/output. zip jenkins. qa.ubuntu. com/job/ mir-mediumtests -builder- vivid-armhf/ 677 jenkins. qa.ubuntu. com/job/ mir-mediumtests -builder- vivid-armhf/ 677/artifact/ work/output/ *zip*/output. zip jenkins. qa.ubuntu. com/job/ mir-mediumtests -runner- mako/3809 s-jenkins. ubuntu- ci:8080/ job/touch- flash-device/ 16790
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/mir- ci/2556/ rebuild
http://