Merge lp:~cemil-azizoglu/mir/create-chain-from-render-surface into lp:mir
- create-chain-from-render-surface
- Merge into development-branch
Proposed by
Cemil Azizoglu
Status: | Superseded |
---|---|
Proposed branch: | lp:~cemil-azizoglu/mir/create-chain-from-render-surface |
Merge into: | lp:mir |
Diff against target: |
1317 lines (+711/-263) 16 files modified
playground/mir_demo_client_chain_jumping_buffers.c (+19/-10) playground/mir_demo_client_prerendered_frames.c (+12/-4) src/client/error_render_surface.cpp (+5/-0) src/client/error_render_surface.h (+1/-0) src/client/mir_connection.cpp (+13/-0) src/client/mir_connection.h (+4/-0) src/client/mir_render_surface.h (+1/-0) src/client/mir_render_surface_api.cpp (+15/-0) src/client/render_surface.cpp (+19/-0) src/client/render_surface.h (+3/-0) src/client/symbols.map (+1/-0) src/include/client/mir_toolkit/mir_render_surface.h (+8/-0) tests/acceptance-tests/staging/test_render_surface.cpp (+112/-14) tests/unit-tests/client/CMakeLists.txt (+1/-0) tests/unit-tests/client/test_mir_connection.cpp (+3/-235) tests/unit-tests/client/test_mir_render_surface.cpp (+494/-0) |
To merge this branch: | bzr merge lp:~cemil-azizoglu/mir/create-chain-from-render-surface |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Mir development team | Pending | ||
Review via email: mp+312187@code.launchpad.net |
This proposal has been superseded by a proposal from 2016-11-30.
Commit message
Get presentation chain from a render surface.
Description of the change
Get presentation chain from a render surface.
I also modified the two presentation chain examples in the playground to use render surfaces.
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'playground/mir_demo_client_chain_jumping_buffers.c' |
2 | --- playground/mir_demo_client_chain_jumping_buffers.c 2016-11-16 12:50:00 +0000 |
3 | +++ playground/mir_demo_client_chain_jumping_buffers.c 2016-11-30 22:47:49 +0000 |
4 | @@ -21,6 +21,7 @@ |
5 | #include <mir_toolkit/mir_buffer_stream.h> |
6 | #include <mir_toolkit/mir_surface.h> |
7 | #include <mir_toolkit/mir_presentation_chain.h> |
8 | +#include <mir_toolkit/mir_render_surface.h> |
9 | #include <mir_toolkit/mir_buffer.h> |
10 | #include <mir_toolkit/version.h> |
11 | #include <sys/types.h> |
12 | @@ -174,9 +175,17 @@ |
13 | unsigned int spare_buffer = 0; |
14 | |
15 | MirPresentationChain* chain[num_chains]; |
16 | + MirRenderSurface* render_surface[num_chains]; |
17 | for(unsigned int i = 0u; i < num_chains; i++) |
18 | { |
19 | - chain[i] = mir_connection_create_presentation_chain_sync(connection); |
20 | + render_surface[i] = mir_connection_create_render_surface_sync(connection, chain_width, chain_height); |
21 | + if (!mir_render_surface_is_valid(render_surface[i])) |
22 | + { |
23 | + printf("could not create render surface\n"); |
24 | + return -1; |
25 | + } |
26 | + |
27 | + chain[i] = mir_render_surface_get_presentation_chain(render_surface[i]); |
28 | if (!mir_presentation_chain_is_valid(chain[i])) |
29 | { |
30 | printf("could not create MirPresentationChain\n"); |
31 | @@ -193,14 +202,14 @@ |
32 | |
33 | //Arrange a 2x2 grid of chains within surface |
34 | MirSurfaceSpec* spec = mir_connection_create_spec_for_normal_surface(connection, width, height, format); |
35 | - mir_surface_spec_add_presentation_chain( |
36 | - spec, chain_width, chain_height, displacement_x, displacement_y, chain[0]); |
37 | - mir_surface_spec_add_presentation_chain( |
38 | - spec, chain_width, chain_height, chain_width, displacement_y, chain[1]); |
39 | - mir_surface_spec_add_presentation_chain( |
40 | - spec, chain_width, chain_height, displacement_x, chain_height, chain[2]); |
41 | - mir_surface_spec_add_presentation_chain( |
42 | - spec, chain_width, chain_height, chain_width, chain_height, chain[3]); |
43 | + mir_surface_spec_add_render_surface( |
44 | + spec, render_surface[0], chain_width, chain_height, displacement_x, displacement_y); |
45 | + mir_surface_spec_add_render_surface( |
46 | + spec, render_surface[1], chain_width, chain_height, chain_width, displacement_y); |
47 | + mir_surface_spec_add_render_surface( |
48 | + spec, render_surface[2], chain_width, chain_height, displacement_x, chain_height); |
49 | + mir_surface_spec_add_render_surface( |
50 | + spec, render_surface[3], chain_width, chain_height, chain_width, chain_height); |
51 | MirSurface* surface = mir_surface_create_sync(spec); |
52 | mir_surface_spec_release(spec); |
53 | |
54 | @@ -256,7 +265,7 @@ |
55 | for (unsigned int i = 0u; i < num_buffers; i++) |
56 | mir_buffer_release(buffer_available[i].buffer); |
57 | for (unsigned int i = 0u; i < num_chains; i++) |
58 | - mir_presentation_chain_release(chain[i]); |
59 | + mir_render_surface_release(render_surface[i]); |
60 | mir_surface_release_sync(surface); |
61 | mir_connection_release(connection); |
62 | return 0; |
63 | |
64 | === modified file 'playground/mir_demo_client_prerendered_frames.c' |
65 | --- playground/mir_demo_client_prerendered_frames.c 2016-11-16 12:50:00 +0000 |
66 | +++ playground/mir_demo_client_prerendered_frames.c 2016-11-30 22:47:49 +0000 |
67 | @@ -21,6 +21,7 @@ |
68 | #include <mir_toolkit/mir_buffer_stream.h> |
69 | #include <mir_toolkit/mir_surface.h> |
70 | #include <mir_toolkit/mir_presentation_chain.h> |
71 | +#include <mir_toolkit/mir_render_surface.h> |
72 | #include <mir_toolkit/mir_buffer.h> |
73 | #include <mir_toolkit/version.h> |
74 | #include <sys/types.h> |
75 | @@ -146,7 +147,14 @@ |
76 | return -1; |
77 | } |
78 | |
79 | - MirPresentationChain* chain = mir_connection_create_presentation_chain_sync(connection); |
80 | + MirRenderSurface* render_surface = mir_connection_create_render_surface_sync(connection, width, height); |
81 | + if (!mir_render_surface_is_valid(render_surface)) |
82 | + { |
83 | + printf("could not create a render surface\n"); |
84 | + return -1; |
85 | + } |
86 | + |
87 | + MirPresentationChain* chain = mir_render_surface_get_presentation_chain(render_surface); |
88 | if (!mir_presentation_chain_is_valid(chain)) |
89 | { |
90 | printf("could not create MirPresentationChain\n"); |
91 | @@ -161,8 +169,8 @@ |
92 | } |
93 | |
94 | MirSurfaceSpec* spec = mir_connection_create_spec_for_normal_surface(connection, width, height, format); |
95 | - mir_surface_spec_add_presentation_chain( |
96 | - spec, width, height, displacement_x, displacement_y, chain); |
97 | + mir_surface_spec_add_render_surface( |
98 | + spec, render_surface, width, height, displacement_x, displacement_y); |
99 | MirSurface* surface = mir_surface_create_sync(spec); |
100 | if (!mir_surface_is_valid(surface)) |
101 | { |
102 | @@ -224,7 +232,7 @@ |
103 | |
104 | for (i = 0u; i < num_prerendered_frames; i++) |
105 | mir_buffer_release(buffer_available[i].buffer); |
106 | - mir_presentation_chain_release(chain); |
107 | + mir_render_surface_release(render_surface); |
108 | mir_surface_release_sync(surface); |
109 | mir_connection_release(connection); |
110 | return 0; |
111 | |
112 | === modified file 'src/client/error_render_surface.cpp' |
113 | --- src/client/error_render_surface.cpp 2016-11-22 18:44:52 +0000 |
114 | +++ src/client/error_render_surface.cpp 2016-11-30 22:47:49 +0000 |
115 | @@ -60,6 +60,11 @@ |
116 | throw std::runtime_error(error); |
117 | } |
118 | |
119 | +MirPresentationChain* mcl::ErrorRenderSurface::get_presentation_chain() |
120 | +{ |
121 | + throw std::runtime_error(error); |
122 | +} |
123 | + |
124 | char const* mcl::ErrorRenderSurface::get_error_message() const |
125 | { |
126 | return error.c_str(); |
127 | |
128 | === modified file 'src/client/error_render_surface.h' |
129 | --- src/client/error_render_surface.h 2016-11-22 18:44:52 +0000 |
130 | +++ src/client/error_render_surface.h 2016-11-30 22:47:49 +0000 |
131 | @@ -41,6 +41,7 @@ |
132 | int width, int height, |
133 | MirPixelFormat format, |
134 | MirBufferUsage buffer_usage) override; |
135 | + MirPresentationChain* get_presentation_chain() override; |
136 | private: |
137 | std::string const error; |
138 | MirConnection* const connection_; |
139 | |
140 | === modified file 'src/client/mir_connection.cpp' |
141 | --- src/client/mir_connection.cpp 2016-11-22 18:18:59 +0000 |
142 | +++ src/client/mir_connection.cpp 2016-11-30 22:47:49 +0000 |
143 | @@ -1177,6 +1177,19 @@ |
144 | return display_configuration->take_snapshot(); |
145 | } |
146 | |
147 | +std::shared_ptr<mcl::PresentationChain> MirConnection::create_presentation_chain_with_id( |
148 | + MirRenderSurface* render_surface, |
149 | + mir::protobuf::BufferStream const& a_protobuf_bs) |
150 | +{ |
151 | + if (!client_buffer_factory) |
152 | + client_buffer_factory = platform->create_buffer_factory(); |
153 | + auto chain = std::make_shared<mcl::PresentationChain>( |
154 | + this, a_protobuf_bs.id().value(), server, client_buffer_factory, buffer_factory); |
155 | + |
156 | + surface_map->insert(render_surface->stream_id(), chain); |
157 | + return chain; |
158 | +} |
159 | + |
160 | void MirConnection::create_presentation_chain( |
161 | mir_presentation_chain_callback callback, |
162 | void *context) |
163 | |
164 | === modified file 'src/client/mir_connection.h' |
165 | --- src/client/mir_connection.h 2016-11-14 21:59:19 +0000 |
166 | +++ src/client/mir_connection.h 2016-11-30 22:47:49 +0000 |
167 | @@ -67,6 +67,7 @@ |
168 | class AsyncBufferFactory; |
169 | class MirBuffer; |
170 | class BufferStream; |
171 | +class PresentationChain; |
172 | |
173 | namespace rpc |
174 | { |
175 | @@ -170,6 +171,9 @@ |
176 | void create_presentation_chain( |
177 | mir_presentation_chain_callback callback, |
178 | void *context); |
179 | + std::shared_ptr<mir::client::PresentationChain> create_presentation_chain_with_id( |
180 | + MirRenderSurface* render_surface, |
181 | + mir::protobuf::BufferStream const& a_protobuf_bs); |
182 | void release_presentation_chain(MirPresentationChain* context); |
183 | |
184 | void release_consumer_stream(mir::client::ClientBufferStream*); |
185 | |
186 | === modified file 'src/client/mir_render_surface.h' |
187 | --- src/client/mir_render_surface.h 2016-11-22 18:44:52 +0000 |
188 | +++ src/client/mir_render_surface.h 2016-11-30 22:47:49 +0000 |
189 | @@ -36,6 +36,7 @@ |
190 | int width, int height, |
191 | MirPixelFormat format, |
192 | MirBufferUsage buffer_usage) = 0; |
193 | + virtual MirPresentationChain* get_presentation_chain() = 0; |
194 | virtual char const* get_error_message() const = 0; |
195 | virtual ~MirRenderSurface() = default; |
196 | protected: |
197 | |
198 | === modified file 'src/client/mir_render_surface_api.cpp' |
199 | --- src/client/mir_render_surface_api.cpp 2016-11-22 18:44:52 +0000 |
200 | +++ src/client/mir_render_surface_api.cpp 2016-11-30 22:47:49 +0000 |
201 | @@ -189,6 +189,21 @@ |
202 | return nullptr; |
203 | } |
204 | |
205 | +MirPresentationChain* mir_render_surface_get_presentation_chain( |
206 | + MirRenderSurface* render_surface) |
207 | +try |
208 | +{ |
209 | + mir::require(render_surface); |
210 | + auto connection = connection_map.connection(static_cast<void*>(render_surface)); |
211 | + auto rs = connection->connection_surface_map()->render_surface(render_surface); |
212 | + return rs->get_presentation_chain(); |
213 | +} |
214 | +catch (std::exception const& ex) |
215 | +{ |
216 | + MIR_LOG_UNCAUGHT_EXCEPTION(ex); |
217 | + return nullptr; |
218 | +} |
219 | + |
220 | void mir_render_surface_get_size(MirRenderSurface* render_surface, int* width, int* height) |
221 | { |
222 | mir::require(render_surface && width && height); |
223 | |
224 | === modified file 'src/client/render_surface.cpp' |
225 | --- src/client/render_surface.cpp 2016-11-22 18:44:52 +0000 |
226 | +++ src/client/render_surface.cpp 2016-11-30 22:47:49 +0000 |
227 | @@ -61,6 +61,9 @@ |
228 | MirPixelFormat format, |
229 | MirBufferUsage buffer_usage) |
230 | { |
231 | + if (chain_from_id) |
232 | + BOOST_THROW_EXCEPTION(std::logic_error("Already contains a presentation chain")); |
233 | + |
234 | if (!stream_from_id) |
235 | { |
236 | protobuf_bs->set_pixel_format(format); |
237 | @@ -80,6 +83,22 @@ |
238 | dynamic_cast<ClientBufferStream*>(stream_from_id.get())); |
239 | } |
240 | |
241 | +MirPresentationChain* mcl::RenderSurface::get_presentation_chain() |
242 | +{ |
243 | + if (stream_from_id) |
244 | + BOOST_THROW_EXCEPTION(std::logic_error("Already contains a buffer stream")); |
245 | + |
246 | + if (!chain_from_id) |
247 | + { |
248 | + chain_from_id = connection_->create_presentation_chain_with_id(this, |
249 | + *protobuf_bs); |
250 | + //TODO: Figure out how to handle mir_buffer_usage_hardware once |
251 | + // EGL is made to support RSs. |
252 | + } |
253 | + |
254 | + return reinterpret_cast<MirPresentationChain*>(chain_from_id.get()); |
255 | +} |
256 | + |
257 | geom::Size mcl::RenderSurface::size() const |
258 | { |
259 | std::lock_guard<decltype(size_mutex)> lk(size_mutex); |
260 | |
261 | === modified file 'src/client/render_surface.h' |
262 | --- src/client/render_surface.h 2016-11-22 18:44:52 +0000 |
263 | +++ src/client/render_surface.h 2016-11-30 22:47:49 +0000 |
264 | @@ -39,6 +39,7 @@ |
265 | { |
266 | class ClientPlatform; |
267 | class BufferStream; |
268 | +class PresentationChain; |
269 | class RenderSurface : public MirRenderSurface |
270 | { |
271 | public: |
272 | @@ -57,6 +58,7 @@ |
273 | int width, int height, |
274 | MirPixelFormat format, |
275 | MirBufferUsage buffer_usage) override; |
276 | + MirPresentationChain* get_presentation_chain() override; |
277 | |
278 | private: |
279 | MirConnection* const connection_; |
280 | @@ -64,6 +66,7 @@ |
281 | std::shared_ptr<ClientPlatform> platform; |
282 | std::shared_ptr<mir::protobuf::BufferStream> protobuf_bs; |
283 | std::shared_ptr<mir::client::BufferStream> stream_from_id; |
284 | + std::shared_ptr<mir::client::PresentationChain> chain_from_id; |
285 | |
286 | std::mutex mutable size_mutex; |
287 | geometry::Size desired_size; |
288 | |
289 | === modified file 'src/client/symbols.map' |
290 | --- src/client/symbols.map 2016-11-30 11:38:41 +0000 |
291 | +++ src/client/symbols.map 2016-11-30 22:47:49 +0000 |
292 | @@ -388,6 +388,7 @@ |
293 | mir_connection_create_render_surface; |
294 | mir_connection_create_render_surface_sync; |
295 | mir_render_surface_get_buffer_stream; |
296 | + mir_render_surface_get_presentation_chain; |
297 | mir_render_surface_is_valid; |
298 | mir_render_surface_get_error_message; |
299 | mir_render_surface_get_size; |
300 | |
301 | === modified file 'src/include/client/mir_toolkit/mir_render_surface.h' |
302 | --- src/include/client/mir_toolkit/mir_render_surface.h 2016-11-14 22:39:13 +0000 |
303 | +++ src/include/client/mir_toolkit/mir_render_surface.h 2016-11-30 22:47:49 +0000 |
304 | @@ -133,6 +133,14 @@ |
305 | MirBufferUsage usage); |
306 | |
307 | /** |
308 | + * Obtain the presentation chain backing a given render surface |
309 | + * |
310 | + * \return The chain contained in the given render surface |
311 | + */ |
312 | +MirPresentationChain* mir_render_surface_get_presentation_chain( |
313 | + MirRenderSurface* render_surface); |
314 | + |
315 | +/** |
316 | * Set the MirSurfaceSpec to display content contained in a render surface |
317 | * |
318 | * \warning: The initial call to mir_surface_spec_add_render_surface will set |
319 | |
320 | === modified file 'tests/acceptance-tests/staging/test_render_surface.cpp' |
321 | --- tests/acceptance-tests/staging/test_render_surface.cpp 2016-11-23 00:09:04 +0000 |
322 | +++ tests/acceptance-tests/staging/test_render_surface.cpp 2016-11-30 22:47:49 +0000 |
323 | @@ -18,6 +18,7 @@ |
324 | |
325 | #include "mir_toolkit/mir_client_library.h" |
326 | #include "mir_toolkit/mir_render_surface.h" |
327 | +#include "mir_toolkit/mir_presentation_chain.h" |
328 | |
329 | #include "mir/geometry/size.h" |
330 | #include "mir_test_framework/headless_in_process_server.h" |
331 | @@ -57,7 +58,7 @@ |
332 | mir_connection_release(connection); |
333 | } |
334 | |
335 | -TEST_F(RenderSurfaceTest, can_hand_out_buffer_streams) |
336 | +TEST_F(RenderSurfaceTest, can_hand_out_buffer_stream) |
337 | { |
338 | auto connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__); |
339 | |
340 | @@ -98,6 +99,7 @@ |
341 | physical_size.width.as_int(), physical_size.height.as_int(), |
342 | mir_pixel_format_abgr_8888, |
343 | mir_buffer_usage_hardware); |
344 | + |
345 | ASSERT_THAT(bs, NotNull()); |
346 | EXPECT_TRUE(mir_buffer_stream_is_valid(bs)); |
347 | EXPECT_THAT(mir_buffer_stream_get_error_message(bs), StrEq("")); |
348 | @@ -109,32 +111,28 @@ |
349 | TEST_F(RenderSurfaceTest, render_surfaces_without_content_can_be_added_to_spec) |
350 | { |
351 | auto physical_size = logical_size; |
352 | - |
353 | auto connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__); |
354 | |
355 | auto rs = mir_connection_create_render_surface_sync( |
356 | connection, logical_size.width.as_int(), logical_size.height.as_int()); |
357 | - |
358 | auto spec = mir_connection_create_spec_for_normal_surface( |
359 | connection, |
360 | physical_size.width.as_int(), physical_size.height.as_int(), |
361 | mir_pixel_format_invalid); |
362 | - |
363 | mir_surface_spec_add_render_surface( |
364 | spec, rs, logical_size.width.as_int(), logical_size.height.as_int(), 0, 0); |
365 | - |
366 | auto surface = mir_surface_create_sync(spec); |
367 | mir_surface_spec_release(spec); |
368 | |
369 | EXPECT_THAT(surface, IsValid()); |
370 | - |
371 | EXPECT_THAT(mir_surface_get_buffer_stream(surface), Eq(nullptr)); |
372 | + |
373 | mir_render_surface_release(rs); |
374 | mir_surface_release_sync(surface); |
375 | mir_connection_release(connection); |
376 | } |
377 | |
378 | -TEST_F(RenderSurfaceTest, content_can_be_constructed_after_surface_creation) |
379 | +TEST_F(RenderSurfaceTest, stream_can_be_constructed_after_surface_creation) |
380 | { |
381 | int const width{800}, height{600}; |
382 | MirPixelFormat const format{mir_pixel_format_abgr_8888}; |
383 | @@ -143,26 +141,126 @@ |
384 | auto connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__); |
385 | |
386 | auto rs = mir_connection_create_render_surface_sync( |
387 | - connection, logical_size.width.as_int(), logical_size.height.as_int()); |
388 | + connection, logical_size.width.as_int(), logical_size.height.as_int()); |
389 | auto spec = mir_connection_create_spec_for_normal_surface(connection, |
390 | width, height, |
391 | format); |
392 | - |
393 | mir_surface_spec_add_render_surface(spec, rs, width, height, 0, 0); |
394 | - |
395 | auto surface = mir_surface_create_sync(spec); |
396 | mir_surface_spec_release(spec); |
397 | - |
398 | auto bs = mir_render_surface_get_buffer_stream(rs, |
399 | 640, 480, |
400 | format, |
401 | usage); |
402 | |
403 | EXPECT_THAT(surface, IsValid()); |
404 | - |
405 | EXPECT_THAT(mir_surface_get_buffer_stream(surface), Eq(nullptr)); |
406 | EXPECT_TRUE(mir_buffer_stream_is_valid(bs)); |
407 | - mir_render_surface_release(rs); |
408 | - mir_surface_release_sync(surface); |
409 | + |
410 | + mir_render_surface_release(rs); |
411 | + mir_surface_release_sync(surface); |
412 | + mir_connection_release(connection); |
413 | +} |
414 | + |
415 | +TEST_F(RenderSurfaceTest, can_hand_out_presentation_chain) |
416 | +{ |
417 | + auto connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__); |
418 | + |
419 | + auto rs = mir_connection_create_render_surface_sync( |
420 | + connection, logical_size.width.as_int(), logical_size.height.as_int()); |
421 | + |
422 | + auto pc = mir_render_surface_get_presentation_chain(rs); |
423 | + |
424 | + ASSERT_THAT(pc, NotNull()); |
425 | + EXPECT_TRUE(mir_presentation_chain_is_valid(pc)); |
426 | + |
427 | + mir_render_surface_release(rs); |
428 | + mir_connection_release(connection); |
429 | +} |
430 | + |
431 | +TEST_F(RenderSurfaceTest, chain_can_be_constructed_after_surface_creation) |
432 | +{ |
433 | + int const width{800}, height{600}; |
434 | + MirPixelFormat const format{mir_pixel_format_abgr_8888}; |
435 | + |
436 | + auto connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__); |
437 | + |
438 | + auto rs = mir_connection_create_render_surface_sync( |
439 | + connection, logical_size.width.as_int(), logical_size.height.as_int()); |
440 | + auto spec = mir_connection_create_spec_for_normal_surface(connection, |
441 | + width, height, |
442 | + format); |
443 | + mir_surface_spec_add_render_surface(spec, rs, width, height, 0, 0); |
444 | + auto surface = mir_surface_create_sync(spec); |
445 | + mir_surface_spec_release(spec); |
446 | + auto pc = mir_render_surface_get_presentation_chain(rs); |
447 | + |
448 | + EXPECT_THAT(surface, IsValid()); |
449 | + EXPECT_THAT(mir_surface_get_buffer_stream(surface), Eq(nullptr)); |
450 | + EXPECT_TRUE(mir_presentation_chain_is_valid(pc)); |
451 | + |
452 | + mir_render_surface_release(rs); |
453 | + mir_surface_release_sync(surface); |
454 | + mir_connection_release(connection); |
455 | +} |
456 | + |
457 | +TEST_F(RenderSurfaceTest, dont_have_to_release_presentation_chain) |
458 | +{ |
459 | + auto connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__); |
460 | + |
461 | + auto rs = mir_connection_create_render_surface_sync( |
462 | + connection, logical_size.width.as_int(), logical_size.height.as_int()); |
463 | + auto pc = mir_render_surface_get_presentation_chain(rs); |
464 | + |
465 | + ASSERT_THAT(pc, NotNull()); |
466 | + EXPECT_TRUE(mir_presentation_chain_is_valid(pc)); |
467 | + |
468 | + mir_render_surface_release(rs); |
469 | + mir_connection_release(connection); |
470 | +} |
471 | + |
472 | +TEST_F(RenderSurfaceTest, can_hand_out_stream_or_chain_but_not_both) |
473 | +{ |
474 | + auto physical_size = logical_size; |
475 | + auto connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__); |
476 | + |
477 | + { |
478 | + auto rs = mir_connection_create_render_surface_sync( |
479 | + connection, logical_size.width.as_int(), logical_size.height.as_int()); |
480 | + auto pc = mir_render_surface_get_presentation_chain(rs); |
481 | + |
482 | + ASSERT_THAT(pc, NotNull()); |
483 | + EXPECT_TRUE(mir_presentation_chain_is_valid(pc)); |
484 | + |
485 | + auto bs = mir_render_surface_get_buffer_stream( |
486 | + rs, |
487 | + physical_size.width.as_int(), physical_size.height.as_int(), |
488 | + mir_pixel_format_abgr_8888, |
489 | + mir_buffer_usage_hardware); |
490 | + |
491 | + EXPECT_THAT(bs, Eq(nullptr)); |
492 | + |
493 | + mir_render_surface_release(rs); |
494 | + } |
495 | + |
496 | + { |
497 | + auto rs = mir_connection_create_render_surface_sync( |
498 | + connection, logical_size.width.as_int(), logical_size.height.as_int()); |
499 | + auto bs = mir_render_surface_get_buffer_stream( |
500 | + rs, |
501 | + physical_size.width.as_int(), physical_size.height.as_int(), |
502 | + mir_pixel_format_abgr_8888, |
503 | + mir_buffer_usage_hardware); |
504 | + |
505 | + ASSERT_THAT(bs, NotNull()); |
506 | + EXPECT_TRUE(mir_buffer_stream_is_valid(bs)); |
507 | + |
508 | + auto pc = mir_render_surface_get_presentation_chain(rs); |
509 | + |
510 | + EXPECT_THAT(pc, Eq(nullptr)); |
511 | + |
512 | + mir_render_surface_release(rs); |
513 | + } |
514 | + |
515 | mir_connection_release(connection); |
516 | } |
517 | |
518 | === modified file 'tests/unit-tests/client/CMakeLists.txt' |
519 | --- tests/unit-tests/client/CMakeLists.txt 2016-10-26 05:15:38 +0000 |
520 | +++ tests/unit-tests/client/CMakeLists.txt 2016-11-30 22:47:49 +0000 |
521 | @@ -23,6 +23,7 @@ |
522 | ${CMAKE_CURRENT_SOURCE_DIR}/test_error_buffer.cpp |
523 | ${CMAKE_CURRENT_SOURCE_DIR}/test_client_mir_error.cpp |
524 | ${CMAKE_CURRENT_SOURCE_DIR}/test_no_tls_future.cpp |
525 | + ${CMAKE_CURRENT_SOURCE_DIR}/test_mir_render_surface.cpp |
526 | ) |
527 | |
528 | if (NOT MIR_DISABLE_INPUT) |
529 | |
530 | === modified file 'tests/unit-tests/client/test_mir_connection.cpp' |
531 | --- tests/unit-tests/client/test_mir_connection.cpp 2016-11-23 00:09:04 +0000 |
532 | +++ tests/unit-tests/client/test_mir_connection.cpp 2016-11-30 22:47:49 +0000 |
533 | @@ -23,8 +23,6 @@ |
534 | #include "src/client/mir_surface.h" |
535 | #include "src/client/buffer_factory.h" |
536 | #include "src/client/presentation_chain.h" |
537 | -#include "src/client/render_surface.h" |
538 | -#include "src/client/connection_surface_map.h" |
539 | |
540 | #include "mir/client_platform.h" |
541 | #include "mir/client_platform_factory.h" |
542 | @@ -36,7 +34,6 @@ |
543 | #include "mir_toolkit/mir_presentation_chain.h" |
544 | |
545 | #include "src/server/frontend/resource_cache.h" /* needed by test_server.h */ |
546 | -#include "mir/test/fake_shared.h" |
547 | #include "mir/test/test_protobuf_server.h" |
548 | #include "mir/test/stub_server_tool.h" |
549 | #include "mir/test/doubles/mock_mir_buffer.h" |
550 | @@ -57,31 +54,11 @@ |
551 | namespace mev = mir::events; |
552 | namespace md = mir::dispatch; |
553 | namespace geom = mir::geometry; |
554 | -namespace mt = mir::test; |
555 | -namespace mtd = mt::doubles; |
556 | +namespace mtd = mir::test::doubles; |
557 | using namespace testing; |
558 | |
559 | namespace |
560 | { |
561 | - |
562 | -void assign_result(void* result, void** context) |
563 | -{ |
564 | - if (context) |
565 | - *context = result; |
566 | -} |
567 | - |
568 | -struct RenderSurfaceCallback |
569 | -{ |
570 | - static void created(MirRenderSurface* render_surface, void *client_context) |
571 | - { |
572 | - auto const context = reinterpret_cast<RenderSurfaceCallback*>(client_context); |
573 | - context->invoked = true; |
574 | - context->resulting_render_surface = render_surface; |
575 | - } |
576 | - bool invoked = false; |
577 | - MirRenderSurface* resulting_render_surface = nullptr; |
578 | -}; |
579 | - |
580 | struct BufferStreamCallback |
581 | { |
582 | static void created(MirBufferStream* stream, void *client_context) |
583 | @@ -202,15 +179,12 @@ |
584 | auto native_display = std::make_shared<EGLNativeDisplayType>(); |
585 | *native_display = reinterpret_cast<EGLNativeDisplayType>(0x0); |
586 | |
587 | - auto native_window = std::make_shared<EGLNativeWindowType>(); |
588 | - *native_window = reinterpret_cast<EGLNativeWindowType>(0x12345678); |
589 | - |
590 | ON_CALL(*this, create_egl_native_display()) |
591 | .WillByDefault(Return(native_display)); |
592 | ON_CALL(*this, create_buffer_factory()) |
593 | .WillByDefault(Return(std::make_shared<mtd::StubClientBufferFactory>())); |
594 | ON_CALL(*this, create_egl_native_window(_)) |
595 | - .WillByDefault(Return(native_window)); |
596 | + .WillByDefault(Return(std::shared_ptr<EGLNativeWindowType>())); |
597 | ON_CALL(*this, platform_operation(_)) |
598 | .WillByDefault(Return(nullptr)); |
599 | } |
600 | @@ -232,8 +206,7 @@ |
601 | MOCK_METHOD2(use_egl_native_window, void(std::shared_ptr<void>, mcl::EGLNativeSurface*)); |
602 | MOCK_METHOD1(create_egl_native_window, std::shared_ptr<void>(mcl::EGLNativeSurface*)); |
603 | MOCK_METHOD0(create_egl_native_display, std::shared_ptr<EGLNativeDisplayType>()); |
604 | - MOCK_CONST_METHOD2(get_egl_pixel_format, |
605 | - MirPixelFormat(EGLDisplay, EGLConfig)); |
606 | + MOCK_CONST_METHOD2(get_egl_pixel_format, MirPixelFormat(EGLDisplay, EGLConfig)); |
607 | MOCK_METHOD2(request_interface, void*(char const*, int)); |
608 | |
609 | mcl::ClientContext* client_context = nullptr; |
610 | @@ -877,208 +850,3 @@ |
611 | |
612 | connection->release_buffer(&mock_buffer); |
613 | } |
614 | - |
615 | -TEST_F(MirConnectionTest, render_surface_can_be_created_and_released) |
616 | -{ |
617 | - EXPECT_CALL(*mock_channel, on_buffer_stream_create(_,_)) |
618 | - .WillOnce(Invoke([](mp::BufferStream& stream, google::protobuf::Closure*) |
619 | - { |
620 | - stream.mutable_id()->set_value(1); |
621 | - })); |
622 | - |
623 | - connection->connect("MirConnectionTest", connected_callback, 0)->wait_for_all(); |
624 | - |
625 | - void* nw = nullptr; |
626 | - MirRenderSurface* render_surface = nullptr; |
627 | - connection->create_render_surface_with_content( |
628 | - {10, 10}, |
629 | - reinterpret_cast<mir_render_surface_callback>(assign_result), |
630 | - &render_surface, |
631 | - &nw); |
632 | - EXPECT_THAT(render_surface, NotNull()); |
633 | - EXPECT_THAT(nw, NotNull()); |
634 | - EXPECT_THAT(render_surface, Eq(nw)); |
635 | - EXPECT_NO_THROW(connection->release_render_surface_with_content(nw)); |
636 | - |
637 | - connection->disconnect(); |
638 | -} |
639 | - |
640 | -TEST_F(MirConnectionTest, creation_of_render_surface_creates_egl_native_window) |
641 | -{ |
642 | - RenderSurfaceCallback callback; |
643 | - |
644 | - connection->connect("MirConnectionTest", connected_callback, 0)->wait_for_all(); |
645 | - |
646 | - EXPECT_CALL(*mock_platform, create_egl_native_window(nullptr)); |
647 | - EXPECT_CALL(*mock_channel, on_buffer_stream_create(_,_)) |
648 | - .WillOnce(Invoke([](mp::BufferStream& stream, google::protobuf::Closure*) |
649 | - { |
650 | - stream.mutable_id()->set_value(1); |
651 | - })); |
652 | - |
653 | - void* nw = nullptr; |
654 | - connection->create_render_surface_with_content( |
655 | - {10, 10}, |
656 | - &RenderSurfaceCallback::created, |
657 | - &callback, |
658 | - &nw); |
659 | - EXPECT_THAT(nw, NotNull()); |
660 | - EXPECT_TRUE(callback.invoked); |
661 | - EXPECT_THAT(callback.resulting_render_surface, NotNull()); |
662 | - auto rs = connection->connection_surface_map()->render_surface( |
663 | - static_cast<void*>(callback.resulting_render_surface)); |
664 | - EXPECT_TRUE(reinterpret_cast<mcl::RenderSurface*>(rs->valid())); |
665 | -} |
666 | - |
667 | -TEST_F(MirConnectionTest, render_surface_returns_connection) |
668 | -{ |
669 | - MirConnection* conn{ reinterpret_cast<MirConnection*>(0x12345678) }; |
670 | - |
671 | - mcl::RenderSurface rs( |
672 | - conn, nullptr, nullptr, nullptr, {}); |
673 | - EXPECT_THAT(rs.connection(), Eq(conn)); |
674 | -} |
675 | - |
676 | -TEST_F(MirConnectionTest, render_surface_has_correct_id_before_content_creation) |
677 | -{ |
678 | - MirConnection* conn{ reinterpret_cast<MirConnection*>(0x12345678) }; |
679 | - auto id = 123; |
680 | - |
681 | - mp::BufferStream protobuf_bs; |
682 | - mp::BufferStreamId bs_id; |
683 | - |
684 | - bs_id.set_value(id); |
685 | - *protobuf_bs.mutable_id() = bs_id; |
686 | - |
687 | - mcl::RenderSurface rs( |
688 | - conn, nullptr, nullptr, mt::fake_shared(protobuf_bs), {}); |
689 | - EXPECT_THAT(rs.stream_id().as_value(), Eq(id)); |
690 | -} |
691 | - |
692 | -TEST_F(MirConnectionTest, render_surface_can_create_buffer_stream) |
693 | -{ |
694 | - connection->connect("MirConnectionTest", connected_callback, 0)->wait_for_all(); |
695 | - auto id = 123; |
696 | - |
697 | - mp::BufferStream protobuf_bs; |
698 | - mp::BufferStreamId bs_id; |
699 | - |
700 | - bs_id.set_value(id); |
701 | - *protobuf_bs.mutable_id() = bs_id; |
702 | - |
703 | - auto native_window = mock_platform->create_egl_native_window(nullptr); |
704 | - |
705 | - mcl::RenderSurface rs( |
706 | - connection.get(), native_window, nullptr, mt::fake_shared(protobuf_bs), {}); |
707 | - |
708 | - auto bs = rs.get_buffer_stream(2, 2, mir_pixel_format_abgr_8888, |
709 | - mir_buffer_usage_software); |
710 | - |
711 | - EXPECT_THAT(bs, NotNull()); |
712 | -} |
713 | - |
714 | -TEST_F(MirConnectionTest, render_surface_creation_of_buffer_stream_more_than_once_returns_same_object) |
715 | -{ |
716 | - connection->connect("MirConnectionTest", connected_callback, 0)->wait_for_all(); |
717 | - auto id = 123; |
718 | - |
719 | - mp::BufferStream protobuf_bs; |
720 | - mp::BufferStreamId bs_id; |
721 | - |
722 | - bs_id.set_value(id); |
723 | - *protobuf_bs.mutable_id() = bs_id; |
724 | - |
725 | - auto native_window = mock_platform->create_egl_native_window(nullptr); |
726 | - |
727 | - mcl::RenderSurface rs( |
728 | - connection.get(), native_window, mock_platform, mt::fake_shared(protobuf_bs), {}); |
729 | - |
730 | - EXPECT_CALL(*mock_platform, use_egl_native_window(native_window,_)); |
731 | - |
732 | - auto bs1 = rs.get_buffer_stream(2, 2, mir_pixel_format_abgr_8888, |
733 | - mir_buffer_usage_hardware); |
734 | - |
735 | - auto bs2 = rs.get_buffer_stream(2, 2, mir_pixel_format_abgr_8888, |
736 | - mir_buffer_usage_hardware); |
737 | - |
738 | - EXPECT_THAT(bs1, NotNull()); |
739 | - EXPECT_THAT(bs2, NotNull()); |
740 | - EXPECT_THAT(bs1, Eq(bs2)); |
741 | -} |
742 | - |
743 | -TEST_F(MirConnectionTest, render_surface_creation_of_buffer_stream_with_hardware_usage_installs_new_native_window) |
744 | -{ |
745 | - connection->connect("MirConnectionTest", connected_callback, 0)->wait_for_all(); |
746 | - auto id = 123; |
747 | - |
748 | - mp::BufferStream protobuf_bs; |
749 | - mp::BufferStreamId bs_id; |
750 | - |
751 | - bs_id.set_value(id); |
752 | - *protobuf_bs.mutable_id() = bs_id; |
753 | - |
754 | - auto native_window = mock_platform->create_egl_native_window(nullptr); |
755 | - |
756 | - mcl::RenderSurface rs( |
757 | - connection.get(), native_window, mock_platform, mt::fake_shared(protobuf_bs), {}); |
758 | - |
759 | - EXPECT_CALL(*mock_platform, use_egl_native_window(native_window,_)); |
760 | - |
761 | - auto bs = rs.get_buffer_stream(2, 2, mir_pixel_format_abgr_8888, |
762 | - mir_buffer_usage_hardware); |
763 | - |
764 | - EXPECT_THAT(bs, NotNull()); |
765 | -} |
766 | - |
767 | -TEST_F(MirConnectionTest, render_surface_creation_of_buffer_stream_with_software_usage_does_not_install_new_native_window) |
768 | -{ |
769 | - connection->connect("MirConnectionTest", connected_callback, 0)->wait_for_all(); |
770 | - auto id = 123; |
771 | - |
772 | - mp::BufferStream protobuf_bs; |
773 | - mp::BufferStreamId bs_id; |
774 | - |
775 | - bs_id.set_value(id); |
776 | - *protobuf_bs.mutable_id() = bs_id; |
777 | - |
778 | - auto native_window = mock_platform->create_egl_native_window(nullptr); |
779 | - |
780 | - mcl::RenderSurface rs( |
781 | - connection.get(), native_window, mock_platform, mt::fake_shared(protobuf_bs), {}); |
782 | - |
783 | - EXPECT_CALL(*mock_platform, use_egl_native_window(_,_)).Times(0); |
784 | - |
785 | - auto bs = rs.get_buffer_stream(2, 2, mir_pixel_format_abgr_8888, |
786 | - mir_buffer_usage_software); |
787 | - |
788 | - EXPECT_THAT(bs, NotNull()); |
789 | -} |
790 | - |
791 | -TEST_F(MirConnectionTest, render_surface_object_is_invalid_after_creation_exception) |
792 | -{ |
793 | - RenderSurfaceCallback callback; |
794 | - |
795 | - connection->connect("MirConnectionTest", connected_callback, 0)->wait_for_all(); |
796 | - |
797 | - EXPECT_CALL(*mock_channel, on_buffer_stream_create(_,_)) |
798 | - .WillOnce(DoAll( |
799 | - Invoke([](mp::BufferStream&, google::protobuf::Closure* c){ c->Run(); }), |
800 | - Throw(std::runtime_error("Eeek!")))); |
801 | - |
802 | - void* nw = nullptr; |
803 | - connection->create_render_surface_with_content( |
804 | - {10, 10}, |
805 | - &RenderSurfaceCallback::created, |
806 | - &callback, |
807 | - &nw); |
808 | - |
809 | - EXPECT_TRUE(callback.invoked); |
810 | - EXPECT_THAT(callback.resulting_render_surface, NotNull()); |
811 | - auto rs = connection->connection_surface_map()->render_surface( |
812 | - static_cast<void*>(callback.resulting_render_surface)); |
813 | - |
814 | - EXPECT_THAT(rs->get_error_message(), |
815 | - StrEq("Error processing buffer stream response during render " |
816 | - "surface creation: no ID in response (disconnected?)")); |
817 | - EXPECT_FALSE(reinterpret_cast<mcl::RenderSurface*>(rs->valid())); |
818 | -} |
819 | |
820 | === added file 'tests/unit-tests/client/test_mir_render_surface.cpp' |
821 | --- tests/unit-tests/client/test_mir_render_surface.cpp 1970-01-01 00:00:00 +0000 |
822 | +++ tests/unit-tests/client/test_mir_render_surface.cpp 2016-11-30 22:47:49 +0000 |
823 | @@ -0,0 +1,494 @@ |
824 | +/* |
825 | + * Copyright © 2016 Canonical Ltd. |
826 | + * |
827 | + * This program is free software: you can redistribute it and/or modify |
828 | + * it under the terms of the GNU General Public License version 3 as |
829 | + * published by the Free Software Foundation. |
830 | + * |
831 | + * This program is distributed in the hope that it will be useful, |
832 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
833 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
834 | + * GNU General Public License for more details. |
835 | + * |
836 | + * You should have received a copy of the GNU General Public License |
837 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
838 | + * |
839 | + * Authored by: Cemil Azizoglu <cemil.azizoglu@canonical.com> |
840 | + */ |
841 | + |
842 | +#include "src/client/mir_connection.h" |
843 | +#include "src/client/default_connection_configuration.h" |
844 | +#include "src/client/rpc/mir_basic_rpc_channel.h" |
845 | +#include "src/client/render_surface.h" |
846 | +#include "src/client/connection_surface_map.h" |
847 | + |
848 | +#include "mir/client_platform_factory.h" |
849 | +#include "mir/dispatch/dispatchable.h" |
850 | + |
851 | +#include "mir/test/fake_shared.h" |
852 | +#include "mir/test/doubles/stub_client_buffer_factory.h" |
853 | + |
854 | +#include <sys/eventfd.h> |
855 | + |
856 | +#include <gtest/gtest.h> |
857 | +#include <gmock/gmock.h> |
858 | + |
859 | +namespace mcl = mir::client; |
860 | +namespace mclr = mcl::rpc; |
861 | +namespace mp = mir::protobuf; |
862 | +namespace md = mir::dispatch; |
863 | +namespace mt = mir::test; |
864 | +namespace mtd = mt::doubles; |
865 | + |
866 | +using namespace testing; |
867 | + |
868 | +namespace |
869 | +{ |
870 | +void assign_result(void* result, void** context) |
871 | +{ |
872 | + if (context) |
873 | + *context = result; |
874 | +} |
875 | + |
876 | +struct RenderSurfaceCallback |
877 | +{ |
878 | + static void created(MirRenderSurface* render_surface, void *client_context) |
879 | + { |
880 | + auto const context = reinterpret_cast<RenderSurfaceCallback*>(client_context); |
881 | + context->invoked = true; |
882 | + context->resulting_render_surface = render_surface; |
883 | + } |
884 | + bool invoked = false; |
885 | + MirRenderSurface* resulting_render_surface = nullptr; |
886 | +}; |
887 | + |
888 | +struct MockRpcChannel : public mir::client::rpc::MirBasicRpcChannel, |
889 | + public mir::dispatch::Dispatchable |
890 | +{ |
891 | + MockRpcChannel() |
892 | + : pollable_fd{eventfd(0, EFD_CLOEXEC)} |
893 | + { |
894 | + ON_CALL(*this, watch_fd()).WillByDefault(testing::Return(pollable_fd)); |
895 | + } |
896 | + |
897 | + virtual void call_method(std::string const& name, |
898 | + google::protobuf::MessageLite const* /*parameters*/, |
899 | + google::protobuf::MessageLite* response, |
900 | + google::protobuf::Closure* complete) |
901 | + { |
902 | + if (name == "create_buffer_stream") |
903 | + { |
904 | + auto response_message = static_cast<mp::BufferStream*>(response); |
905 | + on_buffer_stream_create(*response_message, complete); |
906 | + } |
907 | + |
908 | + complete->Run(); |
909 | + } |
910 | + |
911 | + MOCK_METHOD2(on_buffer_stream_create, void(mp::BufferStream&, google::protobuf::Closure* complete)); |
912 | + |
913 | + MOCK_CONST_METHOD0(watch_fd, mir::Fd()); |
914 | + MOCK_METHOD1(dispatch, bool(md::FdEvents)); |
915 | + MOCK_CONST_METHOD0(relevant_events, md::FdEvents()); |
916 | +private: |
917 | + mir::Fd pollable_fd; |
918 | +}; |
919 | + |
920 | +struct MockClientPlatform : public mcl::ClientPlatform |
921 | +{ |
922 | + MockClientPlatform() |
923 | + { |
924 | + auto native_window = std::make_shared<EGLNativeWindowType>(); |
925 | + *native_window = reinterpret_cast<EGLNativeWindowType>(0x12345678); |
926 | + |
927 | + ON_CALL(*this, create_buffer_factory()) |
928 | + .WillByDefault(Return(std::make_shared<mtd::StubClientBufferFactory>())); |
929 | + ON_CALL(*this, create_egl_native_window(_)) |
930 | + .WillByDefault(Return(native_window)); |
931 | + } |
932 | + |
933 | + void set_client_context(mcl::ClientContext* ctx) |
934 | + { |
935 | + client_context = ctx; |
936 | + } |
937 | + |
938 | + void populate(MirPlatformPackage& pkg) const override |
939 | + { |
940 | + client_context->populate_server_package(pkg); |
941 | + } |
942 | + |
943 | + MOCK_CONST_METHOD1(convert_native_buffer, MirNativeBuffer*(mir::graphics::NativeBuffer*)); |
944 | + MOCK_CONST_METHOD0(platform_type, MirPlatformType()); |
945 | + MOCK_METHOD1(platform_operation, MirPlatformMessage*(MirPlatformMessage const*)); |
946 | + MOCK_METHOD0(create_buffer_factory, std::shared_ptr<mcl::ClientBufferFactory>()); |
947 | + MOCK_METHOD2(use_egl_native_window, void(std::shared_ptr<void>, mcl::EGLNativeSurface*)); |
948 | + MOCK_METHOD1(create_egl_native_window, std::shared_ptr<void>(mcl::EGLNativeSurface*)); |
949 | + MOCK_METHOD0(create_egl_native_display, std::shared_ptr<EGLNativeDisplayType>()); |
950 | + MOCK_CONST_METHOD2(get_egl_pixel_format, MirPixelFormat(EGLDisplay, EGLConfig)); |
951 | + MOCK_METHOD2(request_interface, void*(char const*, int)); |
952 | + |
953 | + mcl::ClientContext* client_context = nullptr; |
954 | +}; |
955 | + |
956 | +struct StubClientPlatformFactory : public mcl::ClientPlatformFactory |
957 | +{ |
958 | + StubClientPlatformFactory(std::shared_ptr<mcl::ClientPlatform> const& platform) |
959 | + : platform{platform} |
960 | + { |
961 | + } |
962 | + |
963 | + std::shared_ptr<mcl::ClientPlatform> create_client_platform(mcl::ClientContext*) |
964 | + { |
965 | + return platform; |
966 | + } |
967 | + |
968 | + std::shared_ptr<mcl::ClientPlatform> platform; |
969 | +}; |
970 | + |
971 | +void connected_callback(MirConnection* /*connection*/, void* /*client_context*/) |
972 | +{ |
973 | +} |
974 | + |
975 | +class TestConnectionConfiguration : public mcl::DefaultConnectionConfiguration |
976 | +{ |
977 | +public: |
978 | + TestConnectionConfiguration( |
979 | + std::shared_ptr<mcl::ClientPlatform> const& platform, |
980 | + std::shared_ptr<mclr::MirBasicRpcChannel> const& channel) |
981 | + : DefaultConnectionConfiguration(""), |
982 | + platform{platform}, |
983 | + channel{channel} |
984 | + { |
985 | + } |
986 | + |
987 | + std::shared_ptr<mclr::MirBasicRpcChannel> the_rpc_channel() override |
988 | + { |
989 | + return channel; |
990 | + } |
991 | + |
992 | + std::shared_ptr<mcl::ClientPlatformFactory> the_client_platform_factory() override |
993 | + { |
994 | + return std::make_shared<StubClientPlatformFactory>(platform); |
995 | + } |
996 | + |
997 | +private: |
998 | + std::shared_ptr<mcl::ClientPlatform> const platform; |
999 | + std::shared_ptr<mclr::MirBasicRpcChannel> const channel; |
1000 | +}; |
1001 | +} |
1002 | + |
1003 | +struct MirRenderSurfaceTest : public testing::Test |
1004 | +{ |
1005 | + MirRenderSurfaceTest() |
1006 | + : mock_platform{std::make_shared<testing::NiceMock<MockClientPlatform>>()}, |
1007 | + mock_channel{std::make_shared<testing::NiceMock<MockRpcChannel>>()}, |
1008 | + conf{mock_platform, mock_channel}, |
1009 | + connection{std::make_shared<MirConnection>(conf)} |
1010 | + { |
1011 | + mock_platform->set_client_context(connection.get()); |
1012 | + } |
1013 | + |
1014 | + std::shared_ptr<testing::NiceMock<MockClientPlatform>> const mock_platform; |
1015 | + std::shared_ptr<testing::NiceMock<MockRpcChannel>> const mock_channel; |
1016 | + TestConnectionConfiguration conf; |
1017 | + std::shared_ptr<MirConnection> const connection; |
1018 | +}; |
1019 | + |
1020 | +TEST_F(MirRenderSurfaceTest, render_surface_can_be_created_and_released) |
1021 | +{ |
1022 | + EXPECT_CALL(*mock_channel, on_buffer_stream_create(_,_)) |
1023 | + .WillOnce(Invoke([](mp::BufferStream& stream, google::protobuf::Closure*) |
1024 | + { |
1025 | + stream.mutable_id()->set_value(1); |
1026 | + })); |
1027 | + |
1028 | + connection->connect("MirRenderSurfaceTest", connected_callback, 0)->wait_for_all(); |
1029 | + |
1030 | + void* nw = nullptr; |
1031 | + MirRenderSurface* render_surface = nullptr; |
1032 | + connection->create_render_surface_with_content( |
1033 | + {10, 10}, |
1034 | + reinterpret_cast<mir_render_surface_callback>(assign_result), |
1035 | + &render_surface, |
1036 | + &nw); |
1037 | + |
1038 | + EXPECT_THAT(render_surface, NotNull()); |
1039 | + EXPECT_THAT(nw, NotNull()); |
1040 | + EXPECT_THAT(render_surface, Eq(nw)); |
1041 | + EXPECT_NO_THROW(connection->release_render_surface_with_content(nw)); |
1042 | + |
1043 | + connection->disconnect(); |
1044 | +} |
1045 | + |
1046 | +TEST_F(MirRenderSurfaceTest, creation_of_render_surface_creates_egl_native_window) |
1047 | +{ |
1048 | + RenderSurfaceCallback callback; |
1049 | + |
1050 | + connection->connect("MirRenderSurfaceTest", connected_callback, 0)->wait_for_all(); |
1051 | + |
1052 | + EXPECT_CALL(*mock_platform, create_egl_native_window(nullptr)); |
1053 | + EXPECT_CALL(*mock_channel, on_buffer_stream_create(_,_)) |
1054 | + .WillOnce(Invoke([](mp::BufferStream& stream, google::protobuf::Closure*) |
1055 | + { |
1056 | + stream.mutable_id()->set_value(1); |
1057 | + })); |
1058 | + |
1059 | + void* nw = nullptr; |
1060 | + connection->create_render_surface_with_content({10, 10}, |
1061 | + &RenderSurfaceCallback::created, |
1062 | + &callback, |
1063 | + &nw); |
1064 | + |
1065 | + EXPECT_THAT(nw, NotNull()); |
1066 | + EXPECT_TRUE(callback.invoked); |
1067 | + EXPECT_THAT(callback.resulting_render_surface, NotNull()); |
1068 | + |
1069 | + auto rs = connection->connection_surface_map()->render_surface( |
1070 | + static_cast<void*>(callback.resulting_render_surface)); |
1071 | + |
1072 | + EXPECT_TRUE(reinterpret_cast<mcl::RenderSurface*>(rs->valid())); |
1073 | +} |
1074 | + |
1075 | +TEST_F(MirRenderSurfaceTest, render_surface_returns_connection) |
1076 | +{ |
1077 | + MirConnection* conn{ reinterpret_cast<MirConnection*>(0x12345678) }; |
1078 | + |
1079 | + mcl::RenderSurface rs( |
1080 | + conn, nullptr, nullptr, nullptr, {}); |
1081 | + |
1082 | + EXPECT_THAT(rs.connection(), Eq(conn)); |
1083 | +} |
1084 | + |
1085 | +TEST_F(MirRenderSurfaceTest, render_surface_has_correct_id_before_content_creation) |
1086 | +{ |
1087 | + MirConnection* conn{ reinterpret_cast<MirConnection*>(0x12345678) }; |
1088 | + auto id = 123; |
1089 | + |
1090 | + mp::BufferStream protobuf_bs; |
1091 | + mp::BufferStreamId bs_id; |
1092 | + |
1093 | + bs_id.set_value(id); |
1094 | + *protobuf_bs.mutable_id() = bs_id; |
1095 | + |
1096 | + mcl::RenderSurface rs( |
1097 | + conn, nullptr, nullptr, mt::fake_shared(protobuf_bs), {}); |
1098 | + |
1099 | + EXPECT_THAT(rs.stream_id().as_value(), Eq(id)); |
1100 | +} |
1101 | + |
1102 | +TEST_F(MirRenderSurfaceTest, render_surface_can_create_buffer_stream) |
1103 | +{ |
1104 | + connection->connect("MirRenderSurfaceTest", connected_callback, 0)->wait_for_all(); |
1105 | + auto id = 123; |
1106 | + |
1107 | + mp::BufferStream protobuf_bs; |
1108 | + mp::BufferStreamId bs_id; |
1109 | + |
1110 | + bs_id.set_value(id); |
1111 | + *protobuf_bs.mutable_id() = bs_id; |
1112 | + |
1113 | + auto native_window = mock_platform->create_egl_native_window(nullptr); |
1114 | + |
1115 | + mcl::RenderSurface rs( |
1116 | + connection.get(), native_window, nullptr, mt::fake_shared(protobuf_bs), {}); |
1117 | + |
1118 | + auto bs = rs.get_buffer_stream(2, 2, mir_pixel_format_abgr_8888, |
1119 | + mir_buffer_usage_software); |
1120 | + |
1121 | + EXPECT_THAT(bs, NotNull()); |
1122 | +} |
1123 | + |
1124 | +TEST_F(MirRenderSurfaceTest, render_surface_creation_of_buffer_stream_more_than_once_returns_same_object) |
1125 | +{ |
1126 | + connection->connect("MirRenderSurfaceTest", connected_callback, 0)->wait_for_all(); |
1127 | + auto id = 123; |
1128 | + |
1129 | + mp::BufferStream protobuf_bs; |
1130 | + mp::BufferStreamId bs_id; |
1131 | + |
1132 | + bs_id.set_value(id); |
1133 | + *protobuf_bs.mutable_id() = bs_id; |
1134 | + |
1135 | + auto native_window = mock_platform->create_egl_native_window(nullptr); |
1136 | + |
1137 | + mcl::RenderSurface rs( |
1138 | + connection.get(), native_window, mock_platform, mt::fake_shared(protobuf_bs), {}); |
1139 | + |
1140 | + EXPECT_CALL(*mock_platform, use_egl_native_window(native_window,_)); |
1141 | + |
1142 | + auto bs1 = rs.get_buffer_stream(2, 2, mir_pixel_format_abgr_8888, |
1143 | + mir_buffer_usage_hardware); |
1144 | + auto bs2 = rs.get_buffer_stream(2, 2, mir_pixel_format_abgr_8888, |
1145 | + mir_buffer_usage_hardware); |
1146 | + |
1147 | + EXPECT_THAT(bs1, NotNull()); |
1148 | + EXPECT_THAT(bs2, NotNull()); |
1149 | + EXPECT_THAT(bs1, Eq(bs2)); |
1150 | +} |
1151 | + |
1152 | +TEST_F(MirRenderSurfaceTest, render_surface_creation_of_buffer_stream_with_hardware_usage_installs_new_native_window) |
1153 | +{ |
1154 | + connection->connect("MirRenderSurfaceTest", connected_callback, 0)->wait_for_all(); |
1155 | + auto id = 123; |
1156 | + |
1157 | + mp::BufferStream protobuf_bs; |
1158 | + mp::BufferStreamId bs_id; |
1159 | + |
1160 | + bs_id.set_value(id); |
1161 | + *protobuf_bs.mutable_id() = bs_id; |
1162 | + |
1163 | + auto native_window = mock_platform->create_egl_native_window(nullptr); |
1164 | + |
1165 | + mcl::RenderSurface rs( |
1166 | + connection.get(), native_window, mock_platform, mt::fake_shared(protobuf_bs), {}); |
1167 | + |
1168 | + EXPECT_CALL(*mock_platform, use_egl_native_window(native_window,_)); |
1169 | + |
1170 | + auto bs = rs.get_buffer_stream(2, 2, mir_pixel_format_abgr_8888, |
1171 | + mir_buffer_usage_hardware); |
1172 | + |
1173 | + EXPECT_THAT(bs, NotNull()); |
1174 | +} |
1175 | + |
1176 | +TEST_F(MirRenderSurfaceTest, render_surface_creation_of_buffer_stream_with_software_usage_does_not_install_new_native_window) |
1177 | +{ |
1178 | + connection->connect("MirRenderSurfaceTest", connected_callback, 0)->wait_for_all(); |
1179 | + auto id = 123; |
1180 | + |
1181 | + mp::BufferStream protobuf_bs; |
1182 | + mp::BufferStreamId bs_id; |
1183 | + |
1184 | + bs_id.set_value(id); |
1185 | + *protobuf_bs.mutable_id() = bs_id; |
1186 | + |
1187 | + auto native_window = mock_platform->create_egl_native_window(nullptr); |
1188 | + |
1189 | + mcl::RenderSurface rs( |
1190 | + connection.get(), native_window, mock_platform, mt::fake_shared(protobuf_bs), {}); |
1191 | + |
1192 | + EXPECT_CALL(*mock_platform, use_egl_native_window(_,_)).Times(0); |
1193 | + |
1194 | + auto bs = rs.get_buffer_stream(2, 2, mir_pixel_format_abgr_8888, |
1195 | + mir_buffer_usage_software); |
1196 | + |
1197 | + EXPECT_THAT(bs, NotNull()); |
1198 | +} |
1199 | + |
1200 | +TEST_F(MirRenderSurfaceTest, render_surface_object_is_invalid_after_creation_exception) |
1201 | +{ |
1202 | + RenderSurfaceCallback callback; |
1203 | + |
1204 | + connection->connect("MirRenderSurfaceTest", connected_callback, 0)->wait_for_all(); |
1205 | + |
1206 | + EXPECT_CALL(*mock_channel, on_buffer_stream_create(_,_)) |
1207 | + .WillOnce(DoAll( |
1208 | + Invoke([](mp::BufferStream&, google::protobuf::Closure* c){ c->Run(); }), |
1209 | + Throw(std::runtime_error("Eeek!")))); |
1210 | + |
1211 | + void* nw = nullptr; |
1212 | + connection->create_render_surface_with_content({10, 10}, |
1213 | + &RenderSurfaceCallback::created, |
1214 | + &callback, |
1215 | + &nw); |
1216 | + |
1217 | + EXPECT_TRUE(callback.invoked); |
1218 | + EXPECT_THAT(callback.resulting_render_surface, NotNull()); |
1219 | + auto rs = connection->connection_surface_map()->render_surface( |
1220 | + static_cast<void*>(callback.resulting_render_surface)); |
1221 | + EXPECT_THAT(rs->get_error_message(), |
1222 | + StrEq("Error processing buffer stream response during render " |
1223 | + "surface creation: no ID in response (disconnected?)")); |
1224 | + EXPECT_FALSE(reinterpret_cast<mcl::RenderSurface*>(rs->valid())); |
1225 | +} |
1226 | + |
1227 | +TEST_F(MirRenderSurfaceTest, render_surface_can_create_presentation_chain) |
1228 | +{ |
1229 | + connection->connect("MirRenderSurfaceTest", connected_callback, 0)->wait_for_all(); |
1230 | + auto id = 123; |
1231 | + |
1232 | + mp::BufferStream protobuf_bs; |
1233 | + mp::BufferStreamId bs_id; |
1234 | + |
1235 | + bs_id.set_value(id); |
1236 | + *protobuf_bs.mutable_id() = bs_id; |
1237 | + |
1238 | + auto native_window = mock_platform->create_egl_native_window(nullptr); |
1239 | + |
1240 | + mcl::RenderSurface rs( |
1241 | + connection.get(), native_window, nullptr, mt::fake_shared(protobuf_bs), {}); |
1242 | + |
1243 | + auto pc = rs.get_presentation_chain(); |
1244 | + |
1245 | + EXPECT_THAT(pc, NotNull()); |
1246 | +} |
1247 | + |
1248 | +TEST_F(MirRenderSurfaceTest, render_surface_creation_of_presentation_chain_more_than_once_returns_same_object) |
1249 | +{ |
1250 | + connection->connect("MirRenderSurfaceTest", connected_callback, 0)->wait_for_all(); |
1251 | + auto id = 123; |
1252 | + |
1253 | + mp::BufferStream protobuf_bs; |
1254 | + mp::BufferStreamId bs_id; |
1255 | + |
1256 | + bs_id.set_value(id); |
1257 | + *protobuf_bs.mutable_id() = bs_id; |
1258 | + |
1259 | + auto native_window = mock_platform->create_egl_native_window(nullptr); |
1260 | + |
1261 | + mcl::RenderSurface rs( |
1262 | + connection.get(), native_window, mock_platform, mt::fake_shared(protobuf_bs), {}); |
1263 | + |
1264 | + auto pc1 = rs.get_presentation_chain(); |
1265 | + auto pc2 = rs.get_presentation_chain(); |
1266 | + |
1267 | + EXPECT_THAT(pc1, NotNull()); |
1268 | + EXPECT_THAT(pc2, NotNull()); |
1269 | + EXPECT_THAT(pc1, Eq(pc2)); |
1270 | +} |
1271 | + |
1272 | +TEST_F(MirRenderSurfaceTest, can_create_chain_or_stream_but_not_both) |
1273 | +{ |
1274 | + connection->connect("MirRenderSurfaceTest", connected_callback, 0)->wait_for_all(); |
1275 | + auto id = 123; |
1276 | + |
1277 | + mp::BufferStream protobuf_bs; |
1278 | + mp::BufferStreamId bs_id; |
1279 | + |
1280 | + bs_id.set_value(id); |
1281 | + *protobuf_bs.mutable_id() = bs_id; |
1282 | + |
1283 | + auto native_window = mock_platform->create_egl_native_window(nullptr); |
1284 | + |
1285 | + { |
1286 | + mcl::RenderSurface rs(connection.get(), |
1287 | + native_window, |
1288 | + mock_platform, |
1289 | + mt::fake_shared(protobuf_bs), |
1290 | + {}); |
1291 | + |
1292 | + auto bs = rs.get_buffer_stream(2, 2, mir_pixel_format_abgr_8888, |
1293 | + mir_buffer_usage_hardware); |
1294 | + |
1295 | + EXPECT_THAT(bs, NotNull()); |
1296 | + EXPECT_THROW( |
1297 | + { rs.get_presentation_chain(); }, |
1298 | + std::logic_error); |
1299 | + } |
1300 | + |
1301 | + { |
1302 | + mcl::RenderSurface rs(connection.get(), |
1303 | + native_window, |
1304 | + mock_platform, |
1305 | + mt::fake_shared(protobuf_bs), |
1306 | + {}); |
1307 | + |
1308 | + auto pc = rs.get_presentation_chain(); |
1309 | + |
1310 | + EXPECT_THAT(pc, NotNull()); |
1311 | + EXPECT_THROW( |
1312 | + { rs.get_buffer_stream(2, 2, |
1313 | + mir_pixel_format_abgr_8888, |
1314 | + mir_buffer_usage_hardware); }, |
1315 | + std::logic_error); |
1316 | + } |
1317 | +} |