Merge lp:~cemil-azizoglu/mir/egl-native-window-for-PCs into lp:mir
- egl-native-window-for-PCs
- Merge into development-branch
Status: | Work in progress |
---|---|
Proposed branch: | lp:~cemil-azizoglu/mir/egl-native-window-for-PCs |
Merge into: | lp:mir |
Prerequisite: | lp:~kdub/mir/fix-1584784 |
Diff against target: |
2285 lines (+1513/-425) 24 files modified
playground/CMakeLists.txt (+10/-0) playground/eglflash_nbs.c (+155/-0) src/client/CMakeLists.txt (+2/-0) src/client/buffer_semantics.h (+410/-0) src/client/buffer_stream.cpp (+3/-363) src/client/buffer_stream.h (+1/-2) src/client/error_chain.cpp (+5/-0) src/client/error_chain.h (+1/-0) src/client/exchange_semantics.cpp (+173/-0) src/client/exchange_semantics.h (+70/-0) src/client/mir_connection.cpp (+1/-1) src/client/mir_presentation_chain.h (+13/-0) src/client/mir_presentation_chain_api.cpp (+13/-0) src/client/new_buffer_semantics.cpp (+181/-0) src/client/new_buffer_semantics.h (+79/-0) src/client/presentation_chain.cpp (+99/-6) src/client/presentation_chain.h (+31/-4) src/client/server_buffer_semantics.h (+59/-0) src/client/symbols.map (+1/-0) src/include/client/mir_toolkit/mir_presentation_chain.h (+17/-0) tests/unit-tests/client/stub_client_platform.h (+79/-0) tests/unit-tests/client/test_client_buffer_stream.cpp (+2/-43) tests/unit-tests/client/test_connection_resource_map.cpp (+1/-1) tests/unit-tests/client/test_presentation_chain.cpp (+107/-5) |
To merge this branch: | bzr merge lp:~cemil-azizoglu/mir/egl-native-window-for-PCs |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Mir CI Bot | continuous-integration | Needs Fixing | |
Chris Halse Rogers | Disapprove | ||
Kevin DuBois (community) | Needs Fixing | ||
Review via email: mp+296344@code.launchpad.net |
This proposal supersedes a proposal from 2016-06-02.
Commit message
Support for egl native window from presentation chains.
Description of the change
Support for egl native window from presentation chains.
Mir CI Bot (mir-ci-bot) wrote : Posted in a previous version of this proposal | # |
Kevin DuBois (kdub) wrote : Posted in a previous version of this proposal | # |
Planning note:
src/client/
is an abstraction that was meant to help with the transition. Hopefully it goes away soon, an "NewBufferSeman
Needs fixing:
The code needs some of the fixes in lp:~kdub/mir/fix-1584784 in order to avoid reintroducing that bug.
Kevin DuBois (kdub) wrote : Posted in a previous version of this proposal | # |
mir_presentatio
is misleading about what MirPresentation
MirEGLNativeWin
so that its a bit clearer that this more of a helper function to extend the use of MirPresentation
Kevin DuBois (kdub) wrote : Posted in a previous version of this proposal | # |
+ virtual EGLNativeWindowType egl_native_
In the same line of thought, a MirPresentation
This is internal, so can be changed easily so that the EGLNativeWindowType can take the PresentationChain in its constructor. (so its probably non blocking, but is something that needs a cleanup once the buffer_semantics.h header gets cleaned up, as mentioned above)
Kevin DuBois (kdub) wrote : Posted in a previous version of this proposal | # |
Also, I think that MirBufferStream shouldn't go away. It fits a need that the clients have (as well as being used extensively in the wild).
Made some design drawings:
A) How things are in current design:
https:/
B) how things would be with mir_presentatio
https:/
C) How things would be with mir_create_
https:/
A) and C) keep the MirPresentation
Kevin DuBois (kdub) wrote : Posted in a previous version of this proposal | # |
Fixed permissions, hopefully:
A) https:/
B) https:/
C) https:/
Cemil Azizoglu (cemil-azizoglu) wrote : | # |
@kdub, I've changed the name to mir_create_
I'd rather not invest more time into the internal refactoring for now. I have a feeling we'll go back and clean this up with the MirRenderable idea that we discussed over email.
Mir CI Bot (mir-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:3530
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Mir CI Bot (mir-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:3530
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Kevin DuBois (kdub) wrote : | # |
re, refactorings:
If we're pressed for time, I suppose that we can do the refactorings, later, but IMO, delaying a bit to avoid establishing this relationship :
+class PresentationChain : public MirPresentation
internally is worth it.
The external bit (which is the hard part to change), is resolved IMO with the client API name change, thanks.
considerations:
eglflash_nbs could be renamed eglflash_
needs fixings:
src/client/
+namespace
+{
anonymous namespace in header. The code should also be moved to a .cpp file.
The header also seems like we're overexposing some classes when they're not needed elsewhere... ExchangeSemantics doesn't seem like its needed anywhere in the new code. <optional> We could also hide the interface by just exposing the SubmitSemantics class, and then wrapping in buffer_stream.cpp
tests/unit-
should be in tests/include/
Also, we already have mtf::StubClient
* Extract an MirEGLNativeWin
needs an update to
"Create a MirEGLNativeWin
Chris Halse Rogers (raof) wrote : | # |
So, as I've mentioned before, I think that both of these approaches are incorrect; EGL clients shouldn't know that the EGL implementation is using a MirPresentation
We've got this on the agenda for the sprint next week, so I think we should not introduce extra client API that we'll probably immediately deprecate.
- 3531. By Cemil Azizoglu
-
Separate ServerBufferSem
antics interfaces
Mir CI Bot (mir-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:3531
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Unmerged revisions
- 3531. By Cemil Azizoglu
-
Separate ServerBufferSem
antics interfaces - 3530. By Cemil Azizoglu
-
s/mir_presentat
ion_chain_ get_egl_ native_ window/ mir_create_ egl_native_ window - 3529. By Cemil Azizoglu
-
merge with lp:~kdub/mir/fix-1584784
- 3528. By Cemil Azizoglu
-
Do away with extraneous printfs
- 3527. By Cemil Azizoglu
-
Revert x-compile script
- 3526. By Cemil Azizoglu
-
EGLNativeWindowType support for presentation chains
Preview Diff
1 | === modified file 'playground/CMakeLists.txt' |
2 | --- playground/CMakeLists.txt 2016-05-03 06:55:25 +0000 |
3 | +++ playground/CMakeLists.txt 2016-06-03 01:46:54 +0000 |
4 | @@ -28,3 +28,13 @@ |
5 | mirclient |
6 | m |
7 | ) |
8 | + |
9 | +mir_add_wrapped_executable(mir_demo_client_eglflash_nbs |
10 | + eglflash_nbs.c |
11 | +) |
12 | + |
13 | +target_link_libraries(mir_demo_client_eglflash_nbs |
14 | + mirclient |
15 | + ${EGL_LIBRARIES} |
16 | + ${GLESv2_LIBRARIES} |
17 | +) |
18 | |
19 | === added file 'playground/eglflash_nbs.c' |
20 | --- playground/eglflash_nbs.c 1970-01-01 00:00:00 +0000 |
21 | +++ playground/eglflash_nbs.c 2016-06-03 01:46:54 +0000 |
22 | @@ -0,0 +1,155 @@ |
23 | +/* |
24 | + * Trivial GL demo; flashes the screen with nbs. |
25 | + * |
26 | + * Copyright © 2016 Canonical Ltd. |
27 | + * |
28 | + * This program is free software: you can redistribute it and/or modify |
29 | + * it under the terms of the GNU General Public License version 3 as |
30 | + * published by the Free Software Foundation. |
31 | + * |
32 | + * This program is distributed in the hope that it will be useful, |
33 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
34 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
35 | + * GNU General Public License for more details. |
36 | + * |
37 | + * You should have received a copy of the GNU General Public License |
38 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
39 | + * |
40 | + * Author: Cemil Azizoglu <cemil.azizoglu@canonical.com> |
41 | + */ |
42 | + |
43 | +#include <mir_toolkit/mir_client_library.h> |
44 | +#include <mir_toolkit/mir_presentation_chain.h> |
45 | +#include <mir_toolkit/mir_buffer.h> |
46 | + |
47 | +#include <stdio.h> |
48 | +#include <string.h> |
49 | +#include <unistd.h> |
50 | +#include <EGL/egl.h> |
51 | +#include <GLES2/gl2.h> |
52 | +#include <pthread.h> |
53 | + |
54 | +typedef struct Color |
55 | +{ |
56 | + GLfloat r, g, b, a; |
57 | +} Color; |
58 | + |
59 | +#define CHECK(_cond, _err) \ |
60 | + if (!(_cond)) \ |
61 | + { \ |
62 | + printf("%s\n", (_err)); \ |
63 | + return -1; \ |
64 | + } |
65 | + |
66 | +int main(int argc, char *argv[]) |
67 | +{ |
68 | + (void) argc; |
69 | + (void) argv; |
70 | + unsigned int num_frames = 0; |
71 | + const char* appname = "eglnbsdemo"; |
72 | + int width = 100; |
73 | + int height = 100; |
74 | + EGLDisplay egldisplay; |
75 | + EGLSurface eglsurface; |
76 | + EGLint ctxattribs[] = |
77 | + { |
78 | + EGL_CONTEXT_CLIENT_VERSION, 2, |
79 | + EGL_NONE |
80 | + }; |
81 | + EGLConfig eglconfig; |
82 | + EGLint neglconfigs; |
83 | + EGLContext eglctx; |
84 | + EGLBoolean ok; |
85 | + MirConnection* connection = NULL; |
86 | + MirSurface* surface = NULL; |
87 | + MirPresentationChain* chain = NULL; |
88 | + |
89 | + connection = mir_connect_sync(NULL, appname); |
90 | + CHECK(mir_connection_is_valid(connection), "Can't get connection"); |
91 | + |
92 | + egldisplay = eglGetDisplay( |
93 | + mir_connection_get_egl_native_display(connection)); |
94 | + CHECK(egldisplay != EGL_NO_DISPLAY, "Can't eglGetDisplay"); |
95 | + |
96 | + ok = eglInitialize(egldisplay, NULL, NULL); |
97 | + CHECK(ok, "Can't eglInitialize"); |
98 | + |
99 | + const EGLint attribs[] = |
100 | + { |
101 | + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, |
102 | + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, |
103 | + EGL_RED_SIZE, 8, |
104 | + EGL_GREEN_SIZE, 8, |
105 | + EGL_BLUE_SIZE, 8, |
106 | + EGL_ALPHA_SIZE, 8, |
107 | + EGL_NONE |
108 | + }; |
109 | + |
110 | + ok = eglChooseConfig(egldisplay, attribs, &eglconfig, 1, &neglconfigs); |
111 | + CHECK(ok, "Could not eglChooseConfig"); |
112 | + CHECK(neglconfigs > 0, "No EGL config available"); |
113 | + |
114 | + MirPixelFormat pixel_format = |
115 | + mir_connection_get_egl_pixel_format(connection, egldisplay, eglconfig); |
116 | + |
117 | + printf("Mir chose pixel format %d.\n", pixel_format); |
118 | + |
119 | + MirSurfaceSpec *spec = |
120 | + mir_connection_create_spec_for_normal_surface(connection, width, height, pixel_format); |
121 | + |
122 | + CHECK(spec, "Can't create a surface spec"); |
123 | + |
124 | + mir_surface_spec_set_name(spec, appname); |
125 | + |
126 | + chain = mir_connection_create_presentation_chain_sync(connection); |
127 | + CHECK(mir_presentation_chain_is_valid(chain), "Can't create presentation chain"); |
128 | + |
129 | + mir_surface_spec_add_presentation_chain( |
130 | + spec, width, height, 0, 0, chain); |
131 | + |
132 | + surface = mir_surface_create_sync(spec); |
133 | + |
134 | + mir_surface_spec_release(spec); |
135 | + |
136 | + eglsurface = eglCreateWindowSurface(egldisplay, eglconfig, |
137 | + (EGLNativeWindowType)mir_create_egl_native_window(chain, width, height, pixel_format), NULL); |
138 | + |
139 | + CHECK(eglsurface != EGL_NO_SURFACE, "eglCreateWindowSurface failed"); |
140 | + |
141 | + eglctx = eglCreateContext(egldisplay, eglconfig, EGL_NO_CONTEXT, |
142 | + ctxattribs); |
143 | + CHECK(eglctx != EGL_NO_CONTEXT, "eglCreateContext failed"); |
144 | + |
145 | + ok = eglMakeCurrent(egldisplay, eglsurface, eglsurface, eglctx); |
146 | + CHECK(ok, "Can't eglMakeCurrent"); |
147 | + |
148 | + Color red = {1.0f, 0.0f, 0.0f, 1.0f}; |
149 | + Color green = {0.0f, 1.0f, 0.0f, 1.0f}; |
150 | + Color blue = {0.0f, 0.0f, 1.0f, 1.0f}; |
151 | + |
152 | + do |
153 | + { |
154 | + glClearColor(red.r, red.g, red.b, red.a); |
155 | + glClear(GL_COLOR_BUFFER_BIT); |
156 | + eglSwapBuffers(egldisplay, eglsurface); |
157 | + sleep(1); |
158 | + |
159 | + glClearColor(green.r, green.g, green.b, green.a); |
160 | + glClear(GL_COLOR_BUFFER_BIT); |
161 | + eglSwapBuffers(egldisplay, eglsurface); |
162 | + sleep(1); |
163 | + |
164 | + glClearColor(blue.r, blue.g, blue.b, blue.a); |
165 | + glClear(GL_COLOR_BUFFER_BIT); |
166 | + eglSwapBuffers(egldisplay, eglsurface); |
167 | + sleep(1); |
168 | + } while (num_frames++ < 3); |
169 | + |
170 | + eglMakeCurrent(egldisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); |
171 | + eglTerminate(egldisplay); |
172 | + mir_presentation_chain_release(chain); |
173 | + mir_surface_release_sync(surface); |
174 | + mir_connection_release(connection); |
175 | + |
176 | + return 0; |
177 | +} |
178 | |
179 | === modified file 'src/client/CMakeLists.txt' |
180 | --- src/client/CMakeLists.txt 2016-06-02 05:33:50 +0000 |
181 | +++ src/client/CMakeLists.txt 2016-06-03 01:46:54 +0000 |
182 | @@ -88,6 +88,8 @@ |
183 | mir_error.cpp |
184 | mir_error.h |
185 | mir_error_api.cpp |
186 | + exchange_semantics.cpp |
187 | + new_buffer_semantics.cpp |
188 | ${MIR_CLIENT_SOURCES} |
189 | ${CMAKE_SOURCE_DIR}/include/client/mir_toolkit/events/surface_output_event.h |
190 | ${CMAKE_SOURCE_DIR}/include/client/mir_toolkit/mir_display_configuration.h |
191 | |
192 | === added file 'src/client/buffer_semantics.h' |
193 | --- src/client/buffer_semantics.h 1970-01-01 00:00:00 +0000 |
194 | +++ src/client/buffer_semantics.h 2016-06-03 01:46:54 +0000 |
195 | @@ -0,0 +1,410 @@ |
196 | +/* |
197 | + * Copyright © 2016 Canonical Ltd. |
198 | + * |
199 | + * This program is free software: you can redistribute it and/or modify |
200 | + * it under the terms of the GNU Lesser General Public License version 3 as |
201 | + * published by the Free Software Foundation. |
202 | + * |
203 | + * This program is distributed in the hope that it will be useful, |
204 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
205 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
206 | + * GNU Lesser General Public License for more details. |
207 | + * |
208 | + * You should have received a copy of the GNU Lesser General Public License |
209 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
210 | + * |
211 | + * Authored by: Kevin DuBois <kevin.dubois@canonical.com> |
212 | + */ |
213 | + |
214 | +#include "buffer_stream.h" |
215 | +#include "buffer.h" |
216 | +#include "buffer_factory.h" |
217 | +#include "make_protobuf_object.h" |
218 | +#include "mir_connection.h" |
219 | +#include "perf_report.h" |
220 | +#include "logging/perf_report.h" |
221 | +#include "rpc/mir_display_server.h" |
222 | +#include "mir_protobuf.pb.h" |
223 | +#include "buffer_vault.h" |
224 | +#include "protobuf_to_native_buffer.h" |
225 | +#include "buffer.h" |
226 | +#include "connection_surface_map.h" |
227 | + |
228 | +#include "mir/log.h" |
229 | +#include "mir/client_platform.h" |
230 | +#include "mir/frontend/client_constants.h" |
231 | +#include "mir_toolkit/mir_native_buffer.h" |
232 | + |
233 | +#include <boost/throw_exception.hpp> |
234 | +#include <boost/exception/diagnostic_information.hpp> |
235 | + |
236 | +#include <stdexcept> |
237 | + |
238 | +namespace mcl = mir::client; |
239 | +namespace mclr = mir::client::rpc; |
240 | +namespace mf = mir::frontend; |
241 | +namespace mp = mir::protobuf; |
242 | +namespace geom = mir::geometry; |
243 | + |
244 | +namespace mir |
245 | +{ |
246 | +namespace client |
247 | +{ |
248 | +//An internal interface useful in transitioning buffer exchange semantics based on |
249 | +//the BufferStream response provided by the server |
250 | +struct ServerBufferSemantics |
251 | +{ |
252 | + virtual void deposit(protobuf::Buffer const&, mir::optional_value<geometry::Size>, MirPixelFormat) = 0; |
253 | + virtual void set_buffer_cache_size(unsigned int) = 0; |
254 | + virtual std::shared_ptr<mir::client::ClientBuffer> current_buffer() = 0; |
255 | + virtual uint32_t current_buffer_id() = 0; |
256 | + virtual MirWaitHandle* submit(std::function<void()> const&, MirPixelFormat, int stream_id) = 0; |
257 | + virtual void lost_connection() = 0; |
258 | + virtual void set_size(geom::Size) = 0; |
259 | + virtual MirWaitHandle* set_scale(float, mf::BufferStreamId) = 0; |
260 | + virtual void set_interval(int interval) = 0; |
261 | + virtual geom::Size size() const = 0; |
262 | + virtual ~ServerBufferSemantics() = default; |
263 | + ServerBufferSemantics() = default; |
264 | + ServerBufferSemantics(ServerBufferSemantics const&) = delete; |
265 | + ServerBufferSemantics& operator=(ServerBufferSemantics const&) = delete; |
266 | +}; |
267 | +} |
268 | +} |
269 | + |
270 | +namespace |
271 | +{ |
272 | + |
273 | +struct ExchangeSemantics : mcl::ServerBufferSemantics |
274 | +{ |
275 | + ExchangeSemantics( |
276 | + mir::protobuf::DisplayServer& server, |
277 | + std::shared_ptr<mcl::ClientBufferFactory> const& factory, int max_buffers, |
278 | + mp::Buffer const& first_buffer, geom::Size first_size, MirPixelFormat first_pf) : |
279 | + wrapped{factory, max_buffers}, |
280 | + display_server(server), |
281 | + size_(first_size) |
282 | + { |
283 | + wrapped.deposit_package( |
284 | + mcl::protobuf_to_native_buffer(first_buffer), |
285 | + first_buffer.buffer_id(), first_size, first_pf); |
286 | + } |
287 | + |
288 | + void deposit(mp::Buffer const& buffer, mir::optional_value<geom::Size> size, MirPixelFormat pf) override |
289 | + { |
290 | + std::unique_lock<std::mutex> lock(mutex); |
291 | + if (size.is_set()) |
292 | + size_ = size.value(); |
293 | + |
294 | + if (on_incoming_buffer) |
295 | + { |
296 | + wrapped.deposit_package( |
297 | + mcl::protobuf_to_native_buffer(buffer), |
298 | + buffer.buffer_id(), size_, pf); |
299 | + if (on_incoming_buffer) |
300 | + { |
301 | + on_incoming_buffer(); |
302 | + next_buffer_wait_handle.result_received(); |
303 | + on_incoming_buffer = std::function<void()>{}; |
304 | + } |
305 | + } |
306 | + else |
307 | + { |
308 | + incoming_buffers.push(buffer); |
309 | + } |
310 | + } |
311 | + |
312 | + void set_buffer_cache_size(unsigned int sz) override |
313 | + { |
314 | + std::unique_lock<std::mutex> lock(mutex); |
315 | + wrapped.set_max_buffers(sz); |
316 | + } |
317 | + std::shared_ptr<mir::client::ClientBuffer> current_buffer() override |
318 | + { |
319 | + std::unique_lock<std::mutex> lock(mutex); |
320 | + return wrapped.current_buffer(); |
321 | + } |
322 | + uint32_t current_buffer_id() override |
323 | + { |
324 | + std::unique_lock<std::mutex> lock(mutex); |
325 | + if (incoming_buffers.size()) |
326 | + return incoming_buffers.front().buffer_id(); |
327 | + return wrapped.current_buffer_id(); |
328 | + } |
329 | + |
330 | + MirWaitHandle* submit(std::function<void()> const& done, MirPixelFormat pf, int stream_id) override |
331 | + { |
332 | + std::unique_lock<std::mutex> lock(mutex); |
333 | + if (server_connection_lost) |
334 | + BOOST_THROW_EXCEPTION(std::runtime_error("disconnected: no new buffers")); |
335 | + //always submit what we have, whether we have a buffer, or will have to wait for an async reply |
336 | + auto request = mcl::make_protobuf_object<mp::BufferRequest>(); |
337 | + request->mutable_id()->set_value(stream_id); |
338 | + request->mutable_buffer()->set_buffer_id(wrapped.current_buffer_id()); |
339 | + lock.unlock(); |
340 | + |
341 | + display_server.submit_buffer(request.get(), protobuf_void.get(), |
342 | + google::protobuf::NewCallback(google::protobuf::DoNothing)); |
343 | + |
344 | + lock.lock(); |
345 | + if (server_connection_lost) |
346 | + BOOST_THROW_EXCEPTION(std::runtime_error("disconnected: no new buffers")); |
347 | + if (incoming_buffers.empty()) |
348 | + { |
349 | + next_buffer_wait_handle.expect_result(); |
350 | + on_incoming_buffer = done; |
351 | + } |
352 | + else |
353 | + { |
354 | + wrapped.deposit_package( |
355 | + mcl::protobuf_to_native_buffer(incoming_buffers.front()), |
356 | + incoming_buffers.front().buffer_id(), size_, pf); |
357 | + incoming_buffers.pop(); |
358 | + done(); |
359 | + } |
360 | + return &next_buffer_wait_handle; |
361 | + } |
362 | + |
363 | + void lost_connection() override |
364 | + { |
365 | + std::unique_lock<std::mutex> lock(mutex); |
366 | + server_connection_lost = true; |
367 | + if (on_incoming_buffer) |
368 | + { |
369 | + on_incoming_buffer(); |
370 | + on_incoming_buffer = std::function<void()>{}; |
371 | + } |
372 | + if (next_buffer_wait_handle.is_pending()) |
373 | + next_buffer_wait_handle.result_received(); |
374 | + |
375 | + while (!incoming_buffers.empty()) |
376 | + { |
377 | + auto b = incoming_buffers.front(); |
378 | + for (auto i = 0; i < b.fd_size(); i++) |
379 | + close(b.fd(i)); |
380 | + incoming_buffers.pop(); |
381 | + } |
382 | + } |
383 | + |
384 | + void set_size(geom::Size) override |
385 | + { |
386 | + } |
387 | + |
388 | + geom::Size size() const override |
389 | + { |
390 | + std::unique_lock<std::mutex> lk(mutex); |
391 | + return size_; |
392 | + } |
393 | + |
394 | + void on_scale_set(float scale) |
395 | + { |
396 | + std::unique_lock<decltype(mutex)> lock(mutex); |
397 | + scale_ = scale; |
398 | + scale_wait_handle.result_received(); |
399 | + } |
400 | + |
401 | + MirWaitHandle* set_scale(float scale, mf::BufferStreamId stream_id) override |
402 | + { |
403 | + mp::StreamConfiguration configuration; |
404 | + configuration.mutable_id()->set_value(stream_id.as_value()); |
405 | + configuration.set_scale(scale); |
406 | + scale_wait_handle.expect_result(); |
407 | + |
408 | + display_server.configure_buffer_stream(&configuration, protobuf_void.get(), |
409 | + google::protobuf::NewCallback(this, &ExchangeSemantics::on_scale_set, scale)); |
410 | + return &scale_wait_handle; |
411 | + } |
412 | + |
413 | + void set_interval(int) override |
414 | + { |
415 | + } |
416 | + |
417 | + std::mutex mutable mutex; |
418 | + mcl::ClientBufferDepository wrapped; |
419 | + mir::protobuf::DisplayServer& display_server; |
420 | + std::function<void()> on_incoming_buffer; |
421 | + std::queue<mir::protobuf::Buffer> incoming_buffers; |
422 | + std::unique_ptr<mir::protobuf::Void> protobuf_void{std::make_unique<mp::Void>()}; |
423 | + MirWaitHandle next_buffer_wait_handle; |
424 | + bool server_connection_lost {false}; |
425 | + MirWaitHandle scale_wait_handle; |
426 | + float scale_; |
427 | + geom::Size size_; |
428 | +}; |
429 | + |
430 | +class Requests : public mcl::ServerBufferRequests |
431 | +{ |
432 | +public: |
433 | + Requests(mclr::DisplayServer& server, int stream_id) : |
434 | + server(server), |
435 | + stream_id(stream_id) |
436 | + { |
437 | + } |
438 | + |
439 | + void allocate_buffer(geom::Size size, MirPixelFormat format, int usage) override |
440 | + { |
441 | + mp::BufferAllocation request; |
442 | + request.mutable_id()->set_value(stream_id); |
443 | + auto buf_params = request.add_buffer_requests(); |
444 | + buf_params->set_width(size.width.as_int()); |
445 | + buf_params->set_height(size.height.as_int()); |
446 | + buf_params->set_pixel_format(format); |
447 | + buf_params->set_buffer_usage(usage); |
448 | + |
449 | + //note, NewCallback will trigger on exception, deleting this object there |
450 | + auto protobuf_void = new mp::Void; |
451 | + server.allocate_buffers(&request, protobuf_void, |
452 | + google::protobuf::NewCallback(Requests::ignore_response, protobuf_void)); |
453 | + } |
454 | + |
455 | + void free_buffer(int buffer_id) override |
456 | + { |
457 | + mp::BufferRelease request; |
458 | + request.mutable_id()->set_value(stream_id); |
459 | + request.add_buffers()->set_buffer_id(buffer_id); |
460 | + |
461 | + //note, NewCallback will trigger on exception, deleting this object there |
462 | + auto protobuf_void = new mp::Void; |
463 | + server.release_buffers(&request, protobuf_void, |
464 | + google::protobuf::NewCallback(Requests::ignore_response, protobuf_void)); |
465 | + } |
466 | + |
467 | + void submit_buffer(mcl::Buffer& buffer) override |
468 | + { |
469 | + mp::BufferRequest request; |
470 | + request.mutable_id()->set_value(stream_id); |
471 | + request.mutable_buffer()->set_buffer_id(buffer.rpc_id()); |
472 | + |
473 | + //note, NewCallback will trigger on exception, deleting this object there |
474 | + auto protobuf_void = new mp::Void; |
475 | + server.submit_buffer(&request, protobuf_void, |
476 | + google::protobuf::NewCallback(Requests::ignore_response, protobuf_void)); |
477 | + } |
478 | + |
479 | + static void ignore_response(mp::Void* void_response) |
480 | + { |
481 | + delete void_response; |
482 | + } |
483 | + |
484 | +private: |
485 | + mclr::DisplayServer& server; |
486 | + mp::Void protobuf_void; |
487 | + int stream_id; |
488 | +}; |
489 | + |
490 | +struct NewBufferSemantics : mcl::ServerBufferSemantics |
491 | +{ |
492 | + NewBufferSemantics( |
493 | + std::shared_ptr<mcl::ClientBufferFactory> const& factory, |
494 | + std::shared_ptr<mcl::AsyncBufferFactory> const& mirbuffer_factory, |
495 | + std::shared_ptr<mcl::ServerBufferRequests> const& requests, |
496 | + std::weak_ptr<mcl::SurfaceMap> const& surface_map, |
497 | + geom::Size size, MirPixelFormat format, int usage, |
498 | + unsigned int initial_nbuffers) : |
499 | + vault(factory, mirbuffer_factory, requests, surface_map, size, format, usage, initial_nbuffers), |
500 | + current(nullptr), |
501 | + future(vault.withdraw()), |
502 | + size_(size) |
503 | + { |
504 | + } |
505 | + |
506 | + void deposit(mp::Buffer const&, mir::optional_value<geom::Size>, MirPixelFormat) override |
507 | + { |
508 | + } |
509 | + |
510 | + void advance_current_buffer(std::unique_lock<std::mutex>& lk) |
511 | + { |
512 | + lk.unlock(); |
513 | + auto c = future.get(); |
514 | + lk.lock(); |
515 | + current = c; |
516 | + } |
517 | + |
518 | + std::shared_ptr<mir::client::ClientBuffer> current_buffer() override |
519 | + { |
520 | + std::unique_lock<std::mutex> lk(mutex); |
521 | + if (!current) |
522 | + advance_current_buffer(lk); |
523 | + return current->client_buffer(); |
524 | + } |
525 | + |
526 | + uint32_t current_buffer_id() override |
527 | + { |
528 | + std::unique_lock<std::mutex> lk(mutex); |
529 | + if (!current) |
530 | + advance_current_buffer(lk); |
531 | + return current->rpc_id(); |
532 | + } |
533 | + |
534 | + MirWaitHandle* submit(std::function<void()> const& done, MirPixelFormat, int) override |
535 | + { |
536 | + std::unique_lock<std::mutex> lk(mutex); |
537 | + if (!current) |
538 | + advance_current_buffer(lk); |
539 | + auto c = current; |
540 | + current = nullptr; |
541 | + lk.unlock(); |
542 | + |
543 | + vault.deposit(c); |
544 | + auto wh = vault.wire_transfer_outbound(c, done); |
545 | + auto f = vault.withdraw(); |
546 | + lk.lock(); |
547 | + future = std::move(f); |
548 | + return wh; |
549 | + } |
550 | + |
551 | + void set_size(geom::Size size) override |
552 | + { |
553 | + { |
554 | + std::unique_lock<std::mutex> lk(mutex); |
555 | + size_ = size; |
556 | + } |
557 | + vault.set_size(size); |
558 | + } |
559 | + |
560 | + geom::Size size() const override |
561 | + { |
562 | + std::unique_lock<std::mutex> lk(mutex); |
563 | + return size_; |
564 | + } |
565 | + |
566 | + void lost_connection() override |
567 | + { |
568 | + vault.disconnected(); |
569 | + } |
570 | + |
571 | + void set_buffer_cache_size(unsigned int) override |
572 | + { |
573 | + } |
574 | + |
575 | + MirWaitHandle* set_scale(float scale, mf::BufferStreamId) override |
576 | + { |
577 | + scale_wait_handle.expect_result(); |
578 | + scale_wait_handle.result_received(); |
579 | + vault.set_scale(scale); |
580 | + return &scale_wait_handle; |
581 | + } |
582 | + |
583 | + void set_interval(int interval) override |
584 | + { |
585 | + std::unique_lock<decltype(mutex)> lk(mutex); |
586 | + interval = std::max(0, std::min(1, interval)); |
587 | + if (current_swap_interval == interval) |
588 | + return; |
589 | + if (interval == 0) |
590 | + vault.increase_buffer_count(); |
591 | + else |
592 | + vault.decrease_buffer_count(); |
593 | + current_swap_interval = interval; |
594 | + } |
595 | + |
596 | + mcl::BufferVault vault; |
597 | + std::mutex mutable mutex; |
598 | + std::shared_ptr<mcl::Buffer> current{nullptr}; |
599 | + mir::client::NoTLSFuture<std::shared_ptr<mcl::Buffer>> future; |
600 | + MirWaitHandle scale_wait_handle; |
601 | + int current_swap_interval = 1; |
602 | + geom::Size size_; |
603 | +}; |
604 | + |
605 | +} |
606 | |
607 | === modified file 'src/client/buffer_stream.cpp' |
608 | --- src/client/buffer_stream.cpp 2016-06-03 01:46:54 +0000 |
609 | +++ src/client/buffer_stream.cpp 2016-06-03 01:46:54 +0000 |
610 | @@ -37,6 +37,9 @@ |
611 | #include "mir/frontend/client_constants.h" |
612 | #include "mir_toolkit/mir_native_buffer.h" |
613 | |
614 | +#include "exchange_semantics.h" |
615 | +#include "new_buffer_semantics.h" |
616 | + |
617 | #include <boost/throw_exception.hpp> |
618 | #include <boost/exception/diagnostic_information.hpp> |
619 | |
620 | @@ -51,369 +54,6 @@ |
621 | |
622 | namespace gp = google::protobuf; |
623 | |
624 | -namespace mir |
625 | -{ |
626 | -namespace client |
627 | -{ |
628 | -//An internal interface useful in transitioning buffer exchange semantics based on |
629 | -//the BufferStream response provided by the server |
630 | -struct ServerBufferSemantics |
631 | -{ |
632 | - virtual void deposit(protobuf::Buffer const&, mir::optional_value<geometry::Size>, MirPixelFormat) = 0; |
633 | - virtual void set_buffer_cache_size(unsigned int) = 0; |
634 | - virtual std::shared_ptr<mir::client::ClientBuffer> current_buffer() = 0; |
635 | - virtual uint32_t current_buffer_id() = 0; |
636 | - virtual MirWaitHandle* submit(std::function<void()> const&, MirPixelFormat, int stream_id) = 0; |
637 | - virtual void lost_connection() = 0; |
638 | - virtual void set_size(geom::Size) = 0; |
639 | - virtual MirWaitHandle* set_scale(float, mf::BufferStreamId) = 0; |
640 | - virtual void set_interval(int interval) = 0; |
641 | - virtual geom::Size size() const = 0; |
642 | - virtual ~ServerBufferSemantics() = default; |
643 | - ServerBufferSemantics() = default; |
644 | - ServerBufferSemantics(ServerBufferSemantics const&) = delete; |
645 | - ServerBufferSemantics& operator=(ServerBufferSemantics const&) = delete; |
646 | -}; |
647 | -} |
648 | -} |
649 | - |
650 | -namespace |
651 | -{ |
652 | - |
653 | -struct ExchangeSemantics : mcl::ServerBufferSemantics |
654 | -{ |
655 | - ExchangeSemantics( |
656 | - mir::protobuf::DisplayServer& server, |
657 | - std::shared_ptr<mcl::ClientBufferFactory> const& factory, int max_buffers, |
658 | - mp::Buffer const& first_buffer, geom::Size first_size, MirPixelFormat first_pf) : |
659 | - wrapped{factory, max_buffers}, |
660 | - display_server(server), |
661 | - size_(first_size) |
662 | - { |
663 | - wrapped.deposit_package( |
664 | - mcl::protobuf_to_native_buffer(first_buffer), |
665 | - first_buffer.buffer_id(), first_size, first_pf); |
666 | - } |
667 | - |
668 | - void deposit(mp::Buffer const& buffer, mir::optional_value<geom::Size> size, MirPixelFormat pf) override |
669 | - { |
670 | - std::unique_lock<std::mutex> lock(mutex); |
671 | - if (size.is_set()) |
672 | - size_ = size.value(); |
673 | - |
674 | - if (on_incoming_buffer) |
675 | - { |
676 | - wrapped.deposit_package( |
677 | - mcl::protobuf_to_native_buffer(buffer), |
678 | - buffer.buffer_id(), size_, pf); |
679 | - if (on_incoming_buffer) |
680 | - { |
681 | - on_incoming_buffer(); |
682 | - next_buffer_wait_handle.result_received(); |
683 | - on_incoming_buffer = std::function<void()>{}; |
684 | - } |
685 | - } |
686 | - else |
687 | - { |
688 | - incoming_buffers.push(buffer); |
689 | - } |
690 | - } |
691 | - |
692 | - void set_buffer_cache_size(unsigned int sz) override |
693 | - { |
694 | - std::unique_lock<std::mutex> lock(mutex); |
695 | - wrapped.set_max_buffers(sz); |
696 | - } |
697 | - std::shared_ptr<mir::client::ClientBuffer> current_buffer() override |
698 | - { |
699 | - std::unique_lock<std::mutex> lock(mutex); |
700 | - return wrapped.current_buffer(); |
701 | - } |
702 | - uint32_t current_buffer_id() override |
703 | - { |
704 | - std::unique_lock<std::mutex> lock(mutex); |
705 | - if (incoming_buffers.size()) |
706 | - return incoming_buffers.front().buffer_id(); |
707 | - return wrapped.current_buffer_id(); |
708 | - } |
709 | - |
710 | - MirWaitHandle* submit(std::function<void()> const& done, MirPixelFormat pf, int stream_id) override |
711 | - { |
712 | - std::unique_lock<std::mutex> lock(mutex); |
713 | - if (server_connection_lost) |
714 | - BOOST_THROW_EXCEPTION(std::runtime_error("disconnected: no new buffers")); |
715 | - //always submit what we have, whether we have a buffer, or will have to wait for an async reply |
716 | - auto request = mcl::make_protobuf_object<mp::BufferRequest>(); |
717 | - request->mutable_id()->set_value(stream_id); |
718 | - request->mutable_buffer()->set_buffer_id(wrapped.current_buffer_id()); |
719 | - lock.unlock(); |
720 | - |
721 | - display_server.submit_buffer(request.get(), protobuf_void.get(), |
722 | - google::protobuf::NewCallback(google::protobuf::DoNothing)); |
723 | - |
724 | - lock.lock(); |
725 | - if (server_connection_lost) |
726 | - BOOST_THROW_EXCEPTION(std::runtime_error("disconnected: no new buffers")); |
727 | - if (incoming_buffers.empty()) |
728 | - { |
729 | - next_buffer_wait_handle.expect_result(); |
730 | - on_incoming_buffer = done; |
731 | - } |
732 | - else |
733 | - { |
734 | - wrapped.deposit_package( |
735 | - mcl::protobuf_to_native_buffer(incoming_buffers.front()), |
736 | - incoming_buffers.front().buffer_id(), size_, pf); |
737 | - incoming_buffers.pop(); |
738 | - done(); |
739 | - } |
740 | - return &next_buffer_wait_handle; |
741 | - } |
742 | - |
743 | - void lost_connection() override |
744 | - { |
745 | - std::unique_lock<std::mutex> lock(mutex); |
746 | - server_connection_lost = true; |
747 | - if (on_incoming_buffer) |
748 | - { |
749 | - on_incoming_buffer(); |
750 | - on_incoming_buffer = std::function<void()>{}; |
751 | - } |
752 | - if (next_buffer_wait_handle.is_pending()) |
753 | - next_buffer_wait_handle.result_received(); |
754 | - |
755 | - while (!incoming_buffers.empty()) |
756 | - { |
757 | - auto b = incoming_buffers.front(); |
758 | - for (auto i = 0; i < b.fd_size(); i++) |
759 | - close(b.fd(i)); |
760 | - incoming_buffers.pop(); |
761 | - } |
762 | - } |
763 | - |
764 | - void set_size(geom::Size) override |
765 | - { |
766 | - } |
767 | - |
768 | - geom::Size size() const override |
769 | - { |
770 | - std::unique_lock<std::mutex> lk(mutex); |
771 | - return size_; |
772 | - } |
773 | - |
774 | - void on_scale_set(float scale) |
775 | - { |
776 | - std::unique_lock<decltype(mutex)> lock(mutex); |
777 | - scale_ = scale; |
778 | - scale_wait_handle.result_received(); |
779 | - } |
780 | - |
781 | - MirWaitHandle* set_scale(float scale, mf::BufferStreamId stream_id) override |
782 | - { |
783 | - mp::StreamConfiguration configuration; |
784 | - configuration.mutable_id()->set_value(stream_id.as_value()); |
785 | - configuration.set_scale(scale); |
786 | - scale_wait_handle.expect_result(); |
787 | - |
788 | - display_server.configure_buffer_stream(&configuration, protobuf_void.get(), |
789 | - google::protobuf::NewCallback(this, &ExchangeSemantics::on_scale_set, scale)); |
790 | - return &scale_wait_handle; |
791 | - } |
792 | - |
793 | - void set_interval(int) override |
794 | - { |
795 | - } |
796 | - |
797 | - std::mutex mutable mutex; |
798 | - mcl::ClientBufferDepository wrapped; |
799 | - mir::protobuf::DisplayServer& display_server; |
800 | - std::function<void()> on_incoming_buffer; |
801 | - std::queue<mir::protobuf::Buffer> incoming_buffers; |
802 | - std::unique_ptr<mir::protobuf::Void> protobuf_void{std::make_unique<mp::Void>()}; |
803 | - MirWaitHandle next_buffer_wait_handle; |
804 | - bool server_connection_lost {false}; |
805 | - MirWaitHandle scale_wait_handle; |
806 | - float scale_; |
807 | - geom::Size size_; |
808 | -}; |
809 | - |
810 | -class Requests : public mcl::ServerBufferRequests |
811 | -{ |
812 | -public: |
813 | - Requests(mclr::DisplayServer& server, int stream_id) : |
814 | - server(server), |
815 | - stream_id(stream_id) |
816 | - { |
817 | - } |
818 | - |
819 | - void allocate_buffer(geom::Size size, MirPixelFormat format, int usage) override |
820 | - { |
821 | - mp::BufferAllocation request; |
822 | - request.mutable_id()->set_value(stream_id); |
823 | - auto buf_params = request.add_buffer_requests(); |
824 | - buf_params->set_width(size.width.as_int()); |
825 | - buf_params->set_height(size.height.as_int()); |
826 | - buf_params->set_pixel_format(format); |
827 | - buf_params->set_buffer_usage(usage); |
828 | - |
829 | - //note, NewCallback will trigger on exception, deleting this object there |
830 | - auto protobuf_void = new mp::Void; |
831 | - server.allocate_buffers(&request, protobuf_void, |
832 | - google::protobuf::NewCallback(Requests::ignore_response, protobuf_void)); |
833 | - } |
834 | - |
835 | - void free_buffer(int buffer_id) override |
836 | - { |
837 | - mp::BufferRelease request; |
838 | - request.mutable_id()->set_value(stream_id); |
839 | - request.add_buffers()->set_buffer_id(buffer_id); |
840 | - |
841 | - //note, NewCallback will trigger on exception, deleting this object there |
842 | - auto protobuf_void = new mp::Void; |
843 | - server.release_buffers(&request, protobuf_void, |
844 | - google::protobuf::NewCallback(Requests::ignore_response, protobuf_void)); |
845 | - } |
846 | - |
847 | - void submit_buffer(mcl::Buffer& buffer) override |
848 | - { |
849 | - mp::BufferRequest request; |
850 | - request.mutable_id()->set_value(stream_id); |
851 | - request.mutable_buffer()->set_buffer_id(buffer.rpc_id()); |
852 | - |
853 | - //note, NewCallback will trigger on exception, deleting this object there |
854 | - auto protobuf_void = new mp::Void; |
855 | - server.submit_buffer(&request, protobuf_void, |
856 | - google::protobuf::NewCallback(Requests::ignore_response, protobuf_void)); |
857 | - } |
858 | - |
859 | - static void ignore_response(mp::Void* void_response) |
860 | - { |
861 | - delete void_response; |
862 | - } |
863 | - |
864 | -private: |
865 | - mclr::DisplayServer& server; |
866 | - mp::Void protobuf_void; |
867 | - int stream_id; |
868 | -}; |
869 | - |
870 | -struct NewBufferSemantics : mcl::ServerBufferSemantics |
871 | -{ |
872 | - NewBufferSemantics( |
873 | - std::shared_ptr<mcl::ClientBufferFactory> const& factory, |
874 | - std::shared_ptr<mcl::AsyncBufferFactory> const& mirbuffer_factory, |
875 | - std::shared_ptr<mcl::ServerBufferRequests> const& requests, |
876 | - std::weak_ptr<mcl::SurfaceMap> const& surface_map, |
877 | - geom::Size size, MirPixelFormat format, int usage, |
878 | - unsigned int initial_nbuffers) : |
879 | - vault(factory, mirbuffer_factory, requests, surface_map, size, format, usage, initial_nbuffers), |
880 | - current(nullptr), |
881 | - future(vault.withdraw()), |
882 | - size_(size) |
883 | - { |
884 | - } |
885 | - |
886 | - void deposit(mp::Buffer const&, mir::optional_value<geom::Size>, MirPixelFormat) override |
887 | - { |
888 | - } |
889 | - |
890 | - void advance_current_buffer(std::unique_lock<std::mutex>& lk) |
891 | - { |
892 | - lk.unlock(); |
893 | - auto c = future.get(); |
894 | - lk.lock(); |
895 | - current = c; |
896 | - } |
897 | - |
898 | - std::shared_ptr<mir::client::ClientBuffer> current_buffer() override |
899 | - { |
900 | - std::unique_lock<std::mutex> lk(mutex); |
901 | - if (!current) |
902 | - advance_current_buffer(lk); |
903 | - return current->client_buffer(); |
904 | - } |
905 | - |
906 | - uint32_t current_buffer_id() override |
907 | - { |
908 | - std::unique_lock<std::mutex> lk(mutex); |
909 | - if (!current) |
910 | - advance_current_buffer(lk); |
911 | - return current->rpc_id(); |
912 | - } |
913 | - |
914 | - MirWaitHandle* submit(std::function<void()> const& done, MirPixelFormat, int) override |
915 | - { |
916 | - std::unique_lock<std::mutex> lk(mutex); |
917 | - if (!current) |
918 | - advance_current_buffer(lk); |
919 | - auto c = current; |
920 | - current = nullptr; |
921 | - lk.unlock(); |
922 | - |
923 | - vault.deposit(c); |
924 | - auto wh = vault.wire_transfer_outbound(c, done); |
925 | - auto f = vault.withdraw(); |
926 | - lk.lock(); |
927 | - future = std::move(f); |
928 | - return wh; |
929 | - } |
930 | - |
931 | - void set_size(geom::Size size) override |
932 | - { |
933 | - { |
934 | - std::unique_lock<std::mutex> lk(mutex); |
935 | - size_ = size; |
936 | - } |
937 | - vault.set_size(size); |
938 | - } |
939 | - |
940 | - geom::Size size() const override |
941 | - { |
942 | - std::unique_lock<std::mutex> lk(mutex); |
943 | - return size_; |
944 | - } |
945 | - |
946 | - void lost_connection() override |
947 | - { |
948 | - vault.disconnected(); |
949 | - } |
950 | - |
951 | - void set_buffer_cache_size(unsigned int) override |
952 | - { |
953 | - } |
954 | - |
955 | - MirWaitHandle* set_scale(float scale, mf::BufferStreamId) override |
956 | - { |
957 | - scale_wait_handle.expect_result(); |
958 | - scale_wait_handle.result_received(); |
959 | - vault.set_scale(scale); |
960 | - return &scale_wait_handle; |
961 | - } |
962 | - |
963 | - void set_interval(int interval) override |
964 | - { |
965 | - std::unique_lock<decltype(mutex)> lk(mutex); |
966 | - interval = std::max(0, std::min(1, interval)); |
967 | - if (current_swap_interval == interval) |
968 | - return; |
969 | - if (interval == 0) |
970 | - vault.increase_buffer_count(); |
971 | - else |
972 | - vault.decrease_buffer_count(); |
973 | - current_swap_interval = interval; |
974 | - } |
975 | - |
976 | - mcl::BufferVault vault; |
977 | - std::mutex mutable mutex; |
978 | - std::shared_ptr<mcl::Buffer> current{nullptr}; |
979 | - mir::client::NoTLSFuture<std::shared_ptr<mcl::Buffer>> future; |
980 | - MirWaitHandle scale_wait_handle; |
981 | - int current_swap_interval = 1; |
982 | - geom::Size size_; |
983 | -}; |
984 | - |
985 | -} |
986 | - |
987 | mcl::BufferStream::BufferStream( |
988 | MirConnection* connection, |
989 | std::shared_ptr<MirWaitHandle> creation_wait_handle, |
990 | |
991 | === modified file 'src/client/buffer_stream.h' |
992 | --- src/client/buffer_stream.h 2016-06-02 05:33:50 +0000 |
993 | +++ src/client/buffer_stream.h 2016-06-03 01:46:54 +0000 |
994 | @@ -24,6 +24,7 @@ |
995 | #include "mir/client_buffer.h" |
996 | #include "client_buffer_stream.h" |
997 | #include "client_buffer_depository.h" |
998 | +#include "server_buffer_semantics.h" |
999 | #include "mir/geometry/size.h" |
1000 | |
1001 | #include "mir_toolkit/client_types.h" |
1002 | @@ -66,8 +67,6 @@ |
1003 | class ClientPlatform; |
1004 | class PerfReport; |
1005 | struct MemoryRegion; |
1006 | -class SurfaceMap; |
1007 | -class ServerBufferSemantics; |
1008 | class BufferStream : public EGLNativeSurface, public ClientBufferStream |
1009 | { |
1010 | public: |
1011 | |
1012 | === modified file 'src/client/error_chain.cpp' |
1013 | --- src/client/error_chain.cpp 2016-06-02 05:33:50 +0000 |
1014 | +++ src/client/error_chain.cpp 2016-06-03 01:46:54 +0000 |
1015 | @@ -51,3 +51,8 @@ |
1016 | { |
1017 | BOOST_THROW_EXCEPTION(std::logic_error("Cannot submit: invalid MirPresentationChain")); |
1018 | } |
1019 | + |
1020 | +EGLNativeWindowType mcl::ErrorChain::egl_native_window(geom::Size, MirPixelFormat) |
1021 | +{ |
1022 | + BOOST_THROW_EXCEPTION(std::logic_error("Cannot get native window: invalid MirPresentationChain")); |
1023 | +} |
1024 | |
1025 | === modified file 'src/client/error_chain.h' |
1026 | --- src/client/error_chain.h 2016-06-02 05:33:50 +0000 |
1027 | +++ src/client/error_chain.h 2016-06-03 01:46:54 +0000 |
1028 | @@ -38,6 +38,7 @@ |
1029 | MirConnection* connection() const override; |
1030 | int rpc_id() const override; |
1031 | char const* error_msg() const override; |
1032 | + EGLNativeWindowType egl_native_window(mir::geometry::Size size, MirPixelFormat pixel_format) override; |
1033 | private: |
1034 | MirConnection* const connection_; |
1035 | int const stream_id; |
1036 | |
1037 | === added file 'src/client/exchange_semantics.cpp' |
1038 | --- src/client/exchange_semantics.cpp 1970-01-01 00:00:00 +0000 |
1039 | +++ src/client/exchange_semantics.cpp 2016-06-03 01:46:54 +0000 |
1040 | @@ -0,0 +1,173 @@ |
1041 | +/* |
1042 | + * Copyright © 2016 Canonical Ltd. |
1043 | + * |
1044 | + * This program is free software: you can redistribute it and/or modify |
1045 | + * it under the terms of the GNU Lesser General Public License version 3 as |
1046 | + * published by the Free Software Foundation. |
1047 | + * |
1048 | + * This program is distributed in the hope that it will be useful, |
1049 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1050 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1051 | + * GNU Lesser General Public License for more details. |
1052 | + * |
1053 | + * You should have received a copy of the GNU Lesser General Public License |
1054 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1055 | + * |
1056 | + * Authored by: Cemil Azizoglu <cemil.azizoglu@canonical.com> |
1057 | + */ |
1058 | + |
1059 | +#include "exchange_semantics.h" |
1060 | +#include "buffer.h" |
1061 | +#include "protobuf_to_native_buffer.h" |
1062 | +#include "make_protobuf_object.h" |
1063 | + |
1064 | +#include <boost/throw_exception.hpp> |
1065 | + |
1066 | +namespace mcl = mir::client; |
1067 | +namespace mf = mir::frontend; |
1068 | +namespace mp = mir::protobuf; |
1069 | +namespace geom = mir::geometry; |
1070 | + |
1071 | +mcl::ExchangeSemantics::ExchangeSemantics( |
1072 | + mp::DisplayServer& server, |
1073 | + std::shared_ptr<ClientBufferFactory> const& factory, int max_buffers, |
1074 | + mp::Buffer const& first_buffer, geom::Size first_size, MirPixelFormat first_pf) : |
1075 | + wrapped{factory, max_buffers}, |
1076 | + display_server(server), |
1077 | + size_(first_size) |
1078 | +{ |
1079 | + wrapped.deposit_package( |
1080 | + mcl::protobuf_to_native_buffer(first_buffer), |
1081 | + first_buffer.buffer_id(), first_size, first_pf); |
1082 | +} |
1083 | + |
1084 | +void mcl::ExchangeSemantics::deposit(mp::Buffer const& buffer, mir::optional_value<geom::Size> size, MirPixelFormat pf) |
1085 | +{ |
1086 | + std::unique_lock<std::mutex> lock(mutex); |
1087 | + if (size.is_set()) |
1088 | + size_ = size.value(); |
1089 | + |
1090 | + if (on_incoming_buffer) |
1091 | + { |
1092 | + wrapped.deposit_package( |
1093 | + mcl::protobuf_to_native_buffer(buffer), |
1094 | + buffer.buffer_id(), size_, pf); |
1095 | + if (on_incoming_buffer) |
1096 | + { |
1097 | + on_incoming_buffer(); |
1098 | + next_buffer_wait_handle.result_received(); |
1099 | + on_incoming_buffer = std::function<void()>{}; |
1100 | + } |
1101 | + } |
1102 | + else |
1103 | + { |
1104 | + incoming_buffers.push(buffer); |
1105 | + } |
1106 | +} |
1107 | + |
1108 | +void mcl::ExchangeSemantics::set_buffer_cache_size(unsigned int sz) |
1109 | +{ |
1110 | + std::unique_lock<std::mutex> lock(mutex); |
1111 | + wrapped.set_max_buffers(sz); |
1112 | +} |
1113 | + |
1114 | +std::shared_ptr<mir::client::ClientBuffer> mcl::ExchangeSemantics::current_buffer() |
1115 | +{ |
1116 | + std::unique_lock<std::mutex> lock(mutex); |
1117 | + return wrapped.current_buffer(); |
1118 | +} |
1119 | + |
1120 | +uint32_t mcl::ExchangeSemantics::current_buffer_id() |
1121 | +{ |
1122 | + std::unique_lock<std::mutex> lock(mutex); |
1123 | + if (incoming_buffers.size()) |
1124 | + return incoming_buffers.front().buffer_id(); |
1125 | + return wrapped.current_buffer_id(); |
1126 | +} |
1127 | + |
1128 | +MirWaitHandle* mcl::ExchangeSemantics::submit(std::function<void()> const& done, MirPixelFormat pf, int stream_id) |
1129 | +{ |
1130 | + std::unique_lock<std::mutex> lock(mutex); |
1131 | + if (server_connection_lost) |
1132 | + BOOST_THROW_EXCEPTION(std::runtime_error("disconnected: no new buffers")); |
1133 | + //always submit what we have, whether we have a buffer, or will have to wait for an async reply |
1134 | + auto request = mcl::make_protobuf_object<mp::BufferRequest>(); |
1135 | + request->mutable_id()->set_value(stream_id); |
1136 | + request->mutable_buffer()->set_buffer_id(wrapped.current_buffer_id()); |
1137 | + lock.unlock(); |
1138 | + |
1139 | + display_server.submit_buffer(request.get(), protobuf_void.get(), |
1140 | + google::protobuf::NewCallback(google::protobuf::DoNothing)); |
1141 | + |
1142 | + lock.lock(); |
1143 | + if (server_connection_lost) |
1144 | + BOOST_THROW_EXCEPTION(std::runtime_error("disconnected: no new buffers")); |
1145 | + if (incoming_buffers.empty()) |
1146 | + { |
1147 | + next_buffer_wait_handle.expect_result(); |
1148 | + on_incoming_buffer = done; |
1149 | + } |
1150 | + else |
1151 | + { |
1152 | + wrapped.deposit_package( |
1153 | + mcl::protobuf_to_native_buffer(incoming_buffers.front()), |
1154 | + incoming_buffers.front().buffer_id(), size_, pf); |
1155 | + incoming_buffers.pop(); |
1156 | + done(); |
1157 | + } |
1158 | + return &next_buffer_wait_handle; |
1159 | +} |
1160 | + |
1161 | +void mcl::ExchangeSemantics::lost_connection() |
1162 | +{ |
1163 | + std::unique_lock<std::mutex> lock(mutex); |
1164 | + server_connection_lost = true; |
1165 | + if (on_incoming_buffer) |
1166 | + { |
1167 | + on_incoming_buffer(); |
1168 | + on_incoming_buffer = std::function<void()>{}; |
1169 | + } |
1170 | + if (next_buffer_wait_handle.is_pending()) |
1171 | + next_buffer_wait_handle.result_received(); |
1172 | + |
1173 | + while (!incoming_buffers.empty()) |
1174 | + { |
1175 | + auto b = incoming_buffers.front(); |
1176 | + for (auto i = 0; i < b.fd_size(); i++) |
1177 | + close(b.fd(i)); |
1178 | + incoming_buffers.pop(); |
1179 | + } |
1180 | +} |
1181 | + |
1182 | +void mcl::ExchangeSemantics::set_size(geom::Size) |
1183 | +{ |
1184 | +} |
1185 | + |
1186 | +geom::Size mcl::ExchangeSemantics::size() const |
1187 | +{ |
1188 | + std::unique_lock<std::mutex> lk(mutex); |
1189 | + return size_; |
1190 | +} |
1191 | + |
1192 | +void mcl::ExchangeSemantics::on_scale_set(float scale) |
1193 | +{ |
1194 | + std::unique_lock<decltype(mutex)> lock(mutex); |
1195 | + scale_ = scale; |
1196 | + scale_wait_handle.result_received(); |
1197 | +} |
1198 | + |
1199 | +MirWaitHandle* mcl::ExchangeSemantics::set_scale(float scale, mf::BufferStreamId stream_id) |
1200 | +{ |
1201 | + mp::StreamConfiguration configuration; |
1202 | + configuration.mutable_id()->set_value(stream_id.as_value()); |
1203 | + configuration.set_scale(scale); |
1204 | + scale_wait_handle.expect_result(); |
1205 | + |
1206 | + display_server.configure_buffer_stream(&configuration, protobuf_void.get(), |
1207 | + google::protobuf::NewCallback(this, &ExchangeSemantics::on_scale_set, scale)); |
1208 | + return &scale_wait_handle; |
1209 | +} |
1210 | + |
1211 | +void mcl::ExchangeSemantics::set_interval(int) |
1212 | +{ |
1213 | +} |
1214 | |
1215 | === added file 'src/client/exchange_semantics.h' |
1216 | --- src/client/exchange_semantics.h 1970-01-01 00:00:00 +0000 |
1217 | +++ src/client/exchange_semantics.h 2016-06-03 01:46:54 +0000 |
1218 | @@ -0,0 +1,70 @@ |
1219 | +/* |
1220 | + * Copyright © 2016 Canonical Ltd. |
1221 | + * |
1222 | + * This program is free software: you can redistribute it and/or modify |
1223 | + * it under the terms of the GNU Lesser General Public License version 3 as |
1224 | + * published by the Free Software Foundation. |
1225 | + * |
1226 | + * This program is distributed in the hope that it will be useful, |
1227 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1228 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1229 | + * GNU Lesser General Public License for more details. |
1230 | + * |
1231 | + * You should have received a copy of the GNU Lesser General Public License |
1232 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1233 | + * |
1234 | + * Authored by: Kevin DuBois <kevin.dubois@canonical.com> |
1235 | + */ |
1236 | + |
1237 | +#ifndef MIR_CLIENT_EXCHANGE_SEMANTICS_H |
1238 | +#define MIR_CLIENT_EXCHANGE_SEMANTICS_H |
1239 | + |
1240 | +#include "server_buffer_semantics.h" |
1241 | +#include <mir/protobuf/display_server.h> |
1242 | +#include "mir/client_buffer_factory.h" |
1243 | +#include "client_buffer_depository.h" |
1244 | +#include "mir_wait_handle.h" |
1245 | + |
1246 | +#include <mutex> |
1247 | +#include <queue> |
1248 | + |
1249 | +namespace mir |
1250 | +{ |
1251 | +namespace client |
1252 | +{ |
1253 | + |
1254 | +struct ExchangeSemantics : ServerBufferSemantics |
1255 | +{ |
1256 | + ExchangeSemantics( |
1257 | + protobuf::DisplayServer& server, |
1258 | + std::shared_ptr<ClientBufferFactory> const& factory, int max_buffers, |
1259 | + protobuf::Buffer const& first_buffer, geometry::Size first_size, MirPixelFormat first_pf); |
1260 | + void deposit(protobuf::Buffer const& buffer, optional_value<geometry::Size> size, MirPixelFormat pf) override; |
1261 | + void set_buffer_cache_size(unsigned int sz) override; |
1262 | + std::shared_ptr<ClientBuffer> current_buffer() override; |
1263 | + uint32_t current_buffer_id() override; |
1264 | + MirWaitHandle* submit(std::function<void()> const& done, MirPixelFormat pf, int stream_id) override; |
1265 | + void lost_connection() override; |
1266 | + void set_size(geometry::Size) override; |
1267 | + geometry::Size size() const override; |
1268 | + void set_interval(int) override; |
1269 | + void on_scale_set(float scale); |
1270 | + MirWaitHandle* set_scale(float scale, frontend::BufferStreamId stream_id) override; |
1271 | + |
1272 | + std::mutex mutable mutex; |
1273 | + ClientBufferDepository wrapped; |
1274 | + protobuf::DisplayServer& display_server; |
1275 | + std::function<void()> on_incoming_buffer; |
1276 | + std::queue<protobuf::Buffer> incoming_buffers; |
1277 | + std::unique_ptr<protobuf::Void> protobuf_void{std::make_unique<protobuf::Void>()}; |
1278 | + MirWaitHandle next_buffer_wait_handle; |
1279 | + bool server_connection_lost {false}; |
1280 | + MirWaitHandle scale_wait_handle; |
1281 | + float scale_; |
1282 | + geometry::Size size_; |
1283 | +}; |
1284 | + |
1285 | +} |
1286 | +} |
1287 | + |
1288 | +#endif /* MIR_CLIENT_EXCHANGE_SEMANTICS_H */ |
1289 | |
1290 | === modified file 'src/client/mir_connection.cpp' |
1291 | --- src/client/mir_connection.cpp 2016-06-02 05:33:50 +0000 |
1292 | +++ src/client/mir_connection.cpp 2016-06-03 01:46:54 +0000 |
1293 | @@ -1180,7 +1180,7 @@ |
1294 | if (!client_buffer_factory) |
1295 | client_buffer_factory = platform->create_buffer_factory(); |
1296 | auto chain = std::make_shared<mcl::PresentationChain>( |
1297 | - this, protobuf_bs->id().value(), server, client_buffer_factory, buffer_factory); |
1298 | + this, protobuf_bs->id().value(), server, platform, client_buffer_factory, buffer_factory, surface_map, nbuffers); |
1299 | |
1300 | surface_map->insert(mf::BufferStreamId(protobuf_bs->id().value()), chain); |
1301 | |
1302 | |
1303 | === modified file 'src/client/mir_presentation_chain.h' |
1304 | --- src/client/mir_presentation_chain.h 2016-03-10 14:30:48 +0000 |
1305 | +++ src/client/mir_presentation_chain.h 2016-06-03 01:46:54 +0000 |
1306 | @@ -22,6 +22,18 @@ |
1307 | #include "mir/geometry/size.h" |
1308 | #include "mir_toolkit/mir_presentation_chain.h" |
1309 | |
1310 | +#include <EGL/eglplatform.h> |
1311 | + |
1312 | +//See comment in client_buffer_stream.h |
1313 | +#include <type_traits> |
1314 | +static_assert( |
1315 | + sizeof(EGLNativeWindowType) == sizeof(void*) && |
1316 | + std::is_pod<EGLNativeWindowType>::value, |
1317 | + "MirPresentationChain requires that EGLNativeWindowType be no-op convertible to void*"); |
1318 | + |
1319 | +#undef EGLNativeWindowType |
1320 | +#define EGLNativeWindowType void* |
1321 | + |
1322 | class MirPresentationChain |
1323 | { |
1324 | public: |
1325 | @@ -30,6 +42,7 @@ |
1326 | virtual MirConnection* connection() const = 0; |
1327 | virtual int rpc_id() const = 0; |
1328 | virtual char const* error_msg() const = 0; |
1329 | + virtual EGLNativeWindowType egl_native_window(mir::geometry::Size size, MirPixelFormat pixel_format) = 0; |
1330 | |
1331 | protected: |
1332 | MirPresentationChain(MirPresentationChain const&) = delete; |
1333 | |
1334 | === modified file 'src/client/mir_presentation_chain_api.cpp' |
1335 | --- src/client/mir_presentation_chain_api.cpp 2016-05-03 06:55:25 +0000 |
1336 | +++ src/client/mir_presentation_chain_api.cpp 2016-06-03 01:46:54 +0000 |
1337 | @@ -124,3 +124,16 @@ |
1338 | { |
1339 | MIR_LOG_UNCAUGHT_EXCEPTION(ex); |
1340 | } |
1341 | + |
1342 | +MirEGLNativeWindowType mir_create_egl_native_window( |
1343 | + MirPresentationChain* presentation_chain, int width, int height, MirPixelFormat pixel_format) |
1344 | +try |
1345 | +{ |
1346 | + mir::require(presentation_chain && mir_presentation_chain_is_valid(presentation_chain)); |
1347 | + return presentation_chain->egl_native_window(mir::geometry::Size{width, height}, pixel_format); |
1348 | +} |
1349 | +catch (std::exception const& ex) |
1350 | +{ |
1351 | + MIR_LOG_UNCAUGHT_EXCEPTION(ex); |
1352 | + return nullptr; |
1353 | +} |
1354 | |
1355 | === added file 'src/client/new_buffer_semantics.cpp' |
1356 | --- src/client/new_buffer_semantics.cpp 1970-01-01 00:00:00 +0000 |
1357 | +++ src/client/new_buffer_semantics.cpp 2016-06-03 01:46:54 +0000 |
1358 | @@ -0,0 +1,181 @@ |
1359 | +/* |
1360 | + * Copyright © 2016 Canonical Ltd. |
1361 | + * |
1362 | + * This program is free software: you can redistribute it and/or modify |
1363 | + * it under the terms of the GNU Lesser General Public License version 3 as |
1364 | + * published by the Free Software Foundation. |
1365 | + * |
1366 | + * This program is distributed in the hope that it will be useful, |
1367 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1368 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1369 | + * GNU Lesser General Public License for more details. |
1370 | + * |
1371 | + * You should have received a copy of the GNU Lesser General Public License |
1372 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1373 | + * |
1374 | + * Authored by: Kevin DuBois <kevin.dubois@canonical.com> |
1375 | + */ |
1376 | + |
1377 | +#include "new_buffer_semantics.h" |
1378 | +#include "buffer.h" |
1379 | + |
1380 | +namespace mcl = mir::client; |
1381 | +namespace mclr = mir::client::rpc; |
1382 | +namespace mf = mir::frontend; |
1383 | +namespace mp = mir::protobuf; |
1384 | +namespace geom = mir::geometry; |
1385 | + |
1386 | +mcl::Requests::Requests(mclr::DisplayServer& server, int stream_id) : |
1387 | + server(server), |
1388 | + stream_id(stream_id) |
1389 | +{ |
1390 | +} |
1391 | + |
1392 | +void mcl::Requests::allocate_buffer(geom::Size size, MirPixelFormat format, int usage) |
1393 | +{ |
1394 | + mp::BufferAllocation request; |
1395 | + request.mutable_id()->set_value(stream_id); |
1396 | + auto buf_params = request.add_buffer_requests(); |
1397 | + buf_params->set_width(size.width.as_int()); |
1398 | + buf_params->set_height(size.height.as_int()); |
1399 | + buf_params->set_pixel_format(format); |
1400 | + buf_params->set_buffer_usage(usage); |
1401 | + |
1402 | + //note, NewCallback will trigger on exception, deleting this object there |
1403 | + auto protobuf_void = new mp::Void; |
1404 | + server.allocate_buffers(&request, protobuf_void, |
1405 | + google::protobuf::NewCallback(Requests::ignore_response, protobuf_void)); |
1406 | +} |
1407 | + |
1408 | +void mcl::Requests::free_buffer(int buffer_id) |
1409 | +{ |
1410 | + mp::BufferRelease request; |
1411 | + request.mutable_id()->set_value(stream_id); |
1412 | + request.add_buffers()->set_buffer_id(buffer_id); |
1413 | + |
1414 | + //note, NewCallback will trigger on exception, deleting this object there |
1415 | + auto protobuf_void = new mp::Void; |
1416 | + server.release_buffers(&request, protobuf_void, |
1417 | + google::protobuf::NewCallback(Requests::ignore_response, protobuf_void)); |
1418 | +} |
1419 | + |
1420 | +void mcl::Requests::submit_buffer(mcl::Buffer& buffer) |
1421 | +{ |
1422 | + mp::BufferRequest request; |
1423 | + request.mutable_id()->set_value(stream_id); |
1424 | + request.mutable_buffer()->set_buffer_id(buffer.rpc_id()); |
1425 | + |
1426 | + //note, NewCallback will trigger on exception, deleting this object there |
1427 | + auto protobuf_void = new mp::Void; |
1428 | + server.submit_buffer(&request, protobuf_void, |
1429 | + google::protobuf::NewCallback(Requests::ignore_response, protobuf_void)); |
1430 | +} |
1431 | + |
1432 | +void mcl::Requests::ignore_response(mp::Void* void_response) |
1433 | +{ |
1434 | + delete void_response; |
1435 | +} |
1436 | + |
1437 | +mcl::NewBufferSemantics::NewBufferSemantics( |
1438 | + std::shared_ptr<mcl::ClientBufferFactory> const& factory, |
1439 | + std::shared_ptr<mcl::AsyncBufferFactory> const& mirbuffer_factory, |
1440 | + std::shared_ptr<mcl::ServerBufferRequests> const& requests, |
1441 | + std::weak_ptr<mcl::SurfaceMap> const& surface_map, |
1442 | + geom::Size size, MirPixelFormat format, int usage, |
1443 | + unsigned int initial_nbuffers) : |
1444 | + vault(factory, mirbuffer_factory, requests, surface_map, size, format, usage, initial_nbuffers), |
1445 | + current(nullptr), |
1446 | + future(vault.withdraw()), |
1447 | + size_(size) |
1448 | +{ |
1449 | +} |
1450 | + |
1451 | +void mcl::NewBufferSemantics::deposit(mp::Buffer const&, mir::optional_value<geom::Size>, MirPixelFormat) |
1452 | +{ |
1453 | +} |
1454 | + |
1455 | +void mcl::NewBufferSemantics::advance_current_buffer(std::unique_lock<std::mutex>& lk) |
1456 | +{ |
1457 | + lk.unlock(); |
1458 | + auto c = future.get(); |
1459 | + lk.lock(); |
1460 | + current = c; |
1461 | +} |
1462 | + |
1463 | +std::shared_ptr<mir::client::ClientBuffer> mcl::NewBufferSemantics::current_buffer() |
1464 | +{ |
1465 | + std::unique_lock<std::mutex> lk(mutex); |
1466 | + if (!current) |
1467 | + advance_current_buffer(lk); |
1468 | + return current->client_buffer(); |
1469 | +} |
1470 | + |
1471 | +uint32_t mcl::NewBufferSemantics::current_buffer_id() |
1472 | +{ |
1473 | + std::unique_lock<std::mutex> lk(mutex); |
1474 | + if (!current) |
1475 | + advance_current_buffer(lk); |
1476 | + return current->rpc_id(); |
1477 | +} |
1478 | + |
1479 | +MirWaitHandle* mcl::NewBufferSemantics::submit(std::function<void()> const& done, MirPixelFormat, int) |
1480 | +{ |
1481 | + std::unique_lock<std::mutex> lk(mutex); |
1482 | + if (!current) |
1483 | + advance_current_buffer(lk); |
1484 | + auto c = current; |
1485 | + current = nullptr; |
1486 | + lk.unlock(); |
1487 | + |
1488 | + vault.deposit(c); |
1489 | + auto wh = vault.wire_transfer_outbound(c, done); |
1490 | + auto f = vault.withdraw(); |
1491 | + lk.lock(); |
1492 | + future = std::move(f); |
1493 | + return wh; |
1494 | +} |
1495 | + |
1496 | +void mcl::NewBufferSemantics::set_size(geom::Size size) |
1497 | +{ |
1498 | + { |
1499 | + std::unique_lock<std::mutex> lk(mutex); |
1500 | + size_ = size; |
1501 | + } |
1502 | + vault.set_size(size); |
1503 | +} |
1504 | + |
1505 | +geom::Size mcl::NewBufferSemantics::size() const |
1506 | +{ |
1507 | + std::unique_lock<std::mutex> lk(mutex); |
1508 | + return size_; |
1509 | +} |
1510 | + |
1511 | +void mcl::NewBufferSemantics::lost_connection() |
1512 | +{ |
1513 | + vault.disconnected(); |
1514 | +} |
1515 | + |
1516 | +void mcl::NewBufferSemantics::set_buffer_cache_size(unsigned int) |
1517 | +{ |
1518 | +} |
1519 | + |
1520 | +MirWaitHandle* mcl::NewBufferSemantics::set_scale(float scale, mf::BufferStreamId) |
1521 | +{ |
1522 | + scale_wait_handle.expect_result(); |
1523 | + scale_wait_handle.result_received(); |
1524 | + vault.set_scale(scale); |
1525 | + return &scale_wait_handle; |
1526 | +} |
1527 | + |
1528 | +void mcl::NewBufferSemantics::set_interval(int interval) |
1529 | +{ |
1530 | + std::unique_lock<decltype(mutex)> lk(mutex); |
1531 | + interval = std::max(0, std::min(1, interval)); |
1532 | + if (current_swap_interval == interval) |
1533 | + return; |
1534 | + if (interval == 0) |
1535 | + vault.increase_buffer_count(); |
1536 | + else |
1537 | + vault.decrease_buffer_count(); |
1538 | + current_swap_interval = interval; |
1539 | +} |
1540 | |
1541 | === added file 'src/client/new_buffer_semantics.h' |
1542 | --- src/client/new_buffer_semantics.h 1970-01-01 00:00:00 +0000 |
1543 | +++ src/client/new_buffer_semantics.h 2016-06-03 01:46:54 +0000 |
1544 | @@ -0,0 +1,79 @@ |
1545 | +/* |
1546 | + * Copyright © 2016 Canonical Ltd. |
1547 | + * |
1548 | + * This program is free software: you can redistribute it and/or modify |
1549 | + * it under the terms of the GNU Lesser General Public License version 3 as |
1550 | + * published by the Free Software Foundation. |
1551 | + * |
1552 | + * This program is distributed in the hope that it will be useful, |
1553 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1554 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1555 | + * GNU Lesser General Public License for more details. |
1556 | + * |
1557 | + * You should have received a copy of the GNU Lesser General Public License |
1558 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1559 | + * |
1560 | + * Authored by: Kevin DuBois <kevin.dubois@canonical.com> |
1561 | + */ |
1562 | + |
1563 | +#ifndef MIR_CLIENT_NEW_BUFFER_SEMANTICS_H |
1564 | +#define MIR_CLIENT_NEW_BUFFER_SEMANTICS_H |
1565 | + |
1566 | +#include "server_buffer_semantics.h" |
1567 | +#include "buffer_vault.h" |
1568 | +#include "rpc/mir_display_server.h" |
1569 | + |
1570 | +namespace mir |
1571 | +{ |
1572 | +namespace client |
1573 | +{ |
1574 | + |
1575 | +class Requests : public ServerBufferRequests |
1576 | +{ |
1577 | +public: |
1578 | + Requests(client::rpc::DisplayServer& server, int stream_id); |
1579 | + void allocate_buffer(geometry::Size size, MirPixelFormat format, int usage) override; |
1580 | + void free_buffer(int buffer_id) override; |
1581 | + void submit_buffer(Buffer& buffer) override; |
1582 | + static void ignore_response(protobuf::Void* void_response); |
1583 | + |
1584 | +private: |
1585 | + client::rpc::DisplayServer& server; |
1586 | + protobuf::Void protobuf_void; |
1587 | + int stream_id; |
1588 | +}; |
1589 | + |
1590 | +struct NewBufferSemantics : ServerBufferSemantics |
1591 | +{ |
1592 | + NewBufferSemantics( |
1593 | + std::shared_ptr<ClientBufferFactory> const& factory, |
1594 | + std::shared_ptr<AsyncBufferFactory> const& mirbuffer_factory, |
1595 | + std::shared_ptr<ServerBufferRequests> const& requests, |
1596 | + std::weak_ptr<SurfaceMap> const& surface_map, |
1597 | + geometry::Size size, MirPixelFormat format, int usage, |
1598 | + unsigned int initial_nbuffers); |
1599 | + void deposit(protobuf::Buffer const&, optional_value<geometry::Size>, MirPixelFormat) override; |
1600 | + void advance_current_buffer(std::unique_lock<std::mutex>& lk); |
1601 | + std::shared_ptr<ClientBuffer> current_buffer() override; |
1602 | + uint32_t current_buffer_id() override; |
1603 | + MirWaitHandle* submit(std::function<void()> const& done, MirPixelFormat, int) override; |
1604 | + void set_size(geometry::Size size) override; |
1605 | + geometry::Size size() const override; |
1606 | + void lost_connection() override; |
1607 | + void set_buffer_cache_size(unsigned int) override; |
1608 | + MirWaitHandle* set_scale(float scale, frontend::BufferStreamId) override; |
1609 | + void set_interval(int interval) override; |
1610 | + |
1611 | + BufferVault vault; |
1612 | + std::mutex mutable mutex; |
1613 | + std::shared_ptr<Buffer> current{nullptr}; |
1614 | + NoTLSFuture<std::shared_ptr<Buffer>> future; |
1615 | + MirWaitHandle scale_wait_handle; |
1616 | + int current_swap_interval = 1; |
1617 | + geometry::Size size_; |
1618 | +}; |
1619 | + |
1620 | +} |
1621 | +} |
1622 | + |
1623 | +#endif /* MIR_CLIENT_NEW_BUFFER_SEMANTICS_H */ |
1624 | |
1625 | === modified file 'src/client/presentation_chain.cpp' |
1626 | --- src/client/presentation_chain.cpp 2016-06-02 05:33:50 +0000 |
1627 | +++ src/client/presentation_chain.cpp 2016-06-03 01:46:54 +0000 |
1628 | @@ -22,6 +22,8 @@ |
1629 | #include "presentation_chain.h" |
1630 | #include "protobuf_to_native_buffer.h" |
1631 | #include "buffer_factory.h" |
1632 | +#include "new_buffer_semantics.h" |
1633 | +#include "mir/client_platform.h" |
1634 | #include <boost/throw_exception.hpp> |
1635 | #include <algorithm> |
1636 | |
1637 | @@ -34,13 +36,22 @@ |
1638 | MirConnection* connection, |
1639 | int stream_id, |
1640 | mir::client::rpc::DisplayServer& server, |
1641 | + std::shared_ptr<ClientPlatform> const& client_platform, |
1642 | std::shared_ptr<mcl::ClientBufferFactory> const& native_buffer_factory, |
1643 | - std::shared_ptr<mcl::AsyncBufferFactory> const& mir_buffer_factory) : |
1644 | - connection_(connection), |
1645 | - stream_id(stream_id), |
1646 | - server(server), |
1647 | - native_buffer_factory(native_buffer_factory), |
1648 | - mir_buffer_factory(mir_buffer_factory) |
1649 | + std::shared_ptr<mcl::AsyncBufferFactory> const& mir_buffer_factory, |
1650 | + std::weak_ptr<SurfaceMap> const& map, |
1651 | + size_t nbuffers) : |
1652 | + connection_(connection), |
1653 | + stream_id(stream_id), |
1654 | + server(server), |
1655 | + client_platform(client_platform), |
1656 | + native_buffer_factory(native_buffer_factory), |
1657 | + mir_buffer_factory(mir_buffer_factory), |
1658 | + egl_native_window_(nullptr), |
1659 | + map(map), |
1660 | + nbuffers(nbuffers), |
1661 | + buffer_depository(nullptr), |
1662 | + egl_native_window_pixel_format(mir_pixel_format_invalid) |
1663 | { |
1664 | } |
1665 | |
1666 | @@ -58,6 +69,9 @@ |
1667 | |
1668 | void mcl::PresentationChain::submit_buffer(MirBuffer* mirbuffer) |
1669 | { |
1670 | + if (egl_native_window_) |
1671 | + BOOST_THROW_EXCEPTION(std::runtime_error("Buffers cannot be submitted when chain is in EGL mode")); |
1672 | + |
1673 | mp::BufferRequest request; |
1674 | { |
1675 | auto buffer = reinterpret_cast<mcl::Buffer*>(mirbuffer); |
1676 | @@ -84,3 +98,82 @@ |
1677 | { |
1678 | return ""; |
1679 | } |
1680 | + |
1681 | +EGLNativeWindowType mcl::PresentationChain::egl_native_window(mir::geometry::Size size, MirPixelFormat pixel_format) |
1682 | +{ |
1683 | + std::unique_lock<decltype(mutex)> lock(mutex); |
1684 | + if (!egl_native_window_) |
1685 | + { |
1686 | + egl_native_window_pixel_format = pixel_format; |
1687 | + buffer_depository = std::make_unique<NewBufferSemantics>( |
1688 | + native_buffer_factory, |
1689 | + mir_buffer_factory, |
1690 | + std::make_shared<Requests>(server, stream_id), |
1691 | + map, |
1692 | + size, |
1693 | + pixel_format, |
1694 | + mir_buffer_usage_hardware, |
1695 | + nbuffers); |
1696 | + |
1697 | + egl_native_window_ = client_platform->create_egl_native_window(this); |
1698 | + } |
1699 | + |
1700 | + return static_cast<EGLNativeWindowType>(egl_native_window_.get()); |
1701 | +} |
1702 | + |
1703 | +////////////////////////////// |
1704 | +// EGLNativeSurface interface |
1705 | +////////////////////////////// |
1706 | + |
1707 | +namespace |
1708 | +{ |
1709 | + const char * const egl_mode_error = "Chain cannot be used in EGL mode"; |
1710 | +} |
1711 | + |
1712 | +MirSurfaceParameters mcl::PresentationChain::get_parameters() const |
1713 | +{ |
1714 | + std::unique_lock<decltype(mutex)> lock(mutex); |
1715 | + |
1716 | + if (!buffer_depository) |
1717 | + BOOST_THROW_EXCEPTION(std::runtime_error(egl_mode_error)); |
1718 | + |
1719 | + auto size = buffer_depository->size(); |
1720 | + |
1721 | + return MirSurfaceParameters{ |
1722 | + "", |
1723 | + size.width.as_int(), |
1724 | + size.height.as_int(), |
1725 | + egl_native_window_pixel_format, |
1726 | + mir_buffer_usage_hardware, |
1727 | + mir_display_output_id_invalid}; |
1728 | +} |
1729 | + |
1730 | +std::shared_ptr<mcl::ClientBuffer> mcl::PresentationChain::get_current_buffer() |
1731 | +{ |
1732 | + { |
1733 | + std::unique_lock<decltype(mutex)> lock(mutex); |
1734 | + if (!buffer_depository) |
1735 | + BOOST_THROW_EXCEPTION(std::runtime_error(egl_mode_error)); |
1736 | + } |
1737 | + return buffer_depository->current_buffer(); |
1738 | +} |
1739 | + |
1740 | +void mcl::PresentationChain::request_and_wait_for_next_buffer() |
1741 | +{ |
1742 | + { |
1743 | + std::unique_lock<decltype(mutex)> lock(mutex); |
1744 | + if (!buffer_depository) |
1745 | + BOOST_THROW_EXCEPTION(std::runtime_error(egl_mode_error)); |
1746 | + } |
1747 | + buffer_depository->submit([](){}, egl_native_window_pixel_format, 0)->wait_for_all(); |
1748 | +} |
1749 | + |
1750 | +void mcl::PresentationChain::request_and_wait_for_configure(MirSurfaceAttrib /*a*/, int /*value*/) |
1751 | +{ |
1752 | + //TODO: implement this function |
1753 | +} |
1754 | + |
1755 | +void mcl::PresentationChain::set_buffer_cache_size(unsigned int) |
1756 | +{ |
1757 | + //TODO: implement this function |
1758 | +} |
1759 | |
1760 | === modified file 'src/client/presentation_chain.h' |
1761 | --- src/client/presentation_chain.h 2016-06-02 05:33:50 +0000 |
1762 | +++ src/client/presentation_chain.h 2016-06-03 01:46:54 +0000 |
1763 | @@ -22,8 +22,10 @@ |
1764 | #include "mir_presentation_chain.h" |
1765 | #include "mir/geometry/size.h" |
1766 | #include "mir_toolkit/mir_presentation_chain.h" |
1767 | +#include "mir/egl_native_surface.h" |
1768 | #include "mir_protobuf.pb.h" |
1769 | #include "buffer.h" |
1770 | +#include "server_buffer_semantics.h" |
1771 | #include <mutex> |
1772 | #include <memory> |
1773 | |
1774 | @@ -34,34 +36,59 @@ |
1775 | class ClientBufferFactory; |
1776 | class ClientBuffer; |
1777 | class AsyncBufferFactory; |
1778 | +class ClientPlatform; |
1779 | +class SurfaceMap; |
1780 | + |
1781 | namespace rpc |
1782 | { |
1783 | class DisplayServer; |
1784 | } |
1785 | |
1786 | -class PresentationChain : public MirPresentationChain |
1787 | +class PresentationChain : public MirPresentationChain, public EGLNativeSurface |
1788 | { |
1789 | public: |
1790 | PresentationChain( |
1791 | MirConnection* connection, |
1792 | int rpc_id, |
1793 | rpc::DisplayServer& server, |
1794 | + std::shared_ptr<ClientPlatform> const& client_platform, |
1795 | std::shared_ptr<ClientBufferFactory> const& native_buffer_factory, |
1796 | - std::shared_ptr<AsyncBufferFactory> const& mir_buffer_factory); |
1797 | + std::shared_ptr<AsyncBufferFactory> const& mir_buffer_factory, |
1798 | + std::weak_ptr<SurfaceMap> const& map, |
1799 | + size_t nbuffers); |
1800 | + |
1801 | void submit_buffer(MirBuffer* buffer) override; |
1802 | MirConnection* connection() const override; |
1803 | int rpc_id() const override; |
1804 | char const* error_msg() const override; |
1805 | + EGLNativeWindowType egl_native_window(mir::geometry::Size size, MirPixelFormat pixel_format) override; |
1806 | + |
1807 | + // EGLNativeSurface interface |
1808 | + std::shared_ptr<ClientBuffer> get_current_buffer() override; |
1809 | + MirSurfaceParameters get_parameters() const override; |
1810 | + void request_and_wait_for_next_buffer() override; |
1811 | + void request_and_wait_for_configure(MirSurfaceAttrib a, int value) override; |
1812 | + void set_buffer_cache_size(unsigned int) override; |
1813 | + |
1814 | +protected: |
1815 | + PresentationChain(PresentationChain const&) = delete; |
1816 | + PresentationChain& operator=(PresentationChain const&) = delete; |
1817 | + |
1818 | private: |
1819 | - |
1820 | MirConnection* const connection_; |
1821 | int const stream_id; |
1822 | rpc::DisplayServer& server; |
1823 | + std::shared_ptr<ClientPlatform> const client_platform; |
1824 | std::shared_ptr<ClientBufferFactory> const native_buffer_factory; |
1825 | std::shared_ptr<AsyncBufferFactory> const mir_buffer_factory; |
1826 | + std::shared_ptr<void> egl_native_window_; |
1827 | + std::weak_ptr<SurfaceMap> const map; |
1828 | + size_t nbuffers; |
1829 | |
1830 | - std::mutex mutex; |
1831 | + mutable std::mutex mutex; |
1832 | std::vector<std::unique_ptr<Buffer>> buffers; |
1833 | + std::unique_ptr<ServerBufferSemantics> buffer_depository; |
1834 | + MirPixelFormat egl_native_window_pixel_format; |
1835 | }; |
1836 | } |
1837 | } |
1838 | |
1839 | === added file 'src/client/server_buffer_semantics.h' |
1840 | --- src/client/server_buffer_semantics.h 1970-01-01 00:00:00 +0000 |
1841 | +++ src/client/server_buffer_semantics.h 2016-06-03 01:46:54 +0000 |
1842 | @@ -0,0 +1,59 @@ |
1843 | +/* |
1844 | + * Copyright © 2016 Canonical Ltd. |
1845 | + * |
1846 | + * This program is free software: you can redistribute it and/or modify |
1847 | + * it under the terms of the GNU Lesser General Public License version 3 as |
1848 | + * published by the Free Software Foundation. |
1849 | + * |
1850 | + * This program is distributed in the hope that it will be useful, |
1851 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1852 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1853 | + * GNU Lesser General Public License for more details. |
1854 | + * |
1855 | + * You should have received a copy of the GNU Lesser General Public License |
1856 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1857 | + * |
1858 | + * Authored by: Kevin DuBois <kevin.dubois@canonical.com> |
1859 | + */ |
1860 | + |
1861 | +#ifndef MIR_CLIENT_SERVER_BUFFER_SEMANTICS_H |
1862 | +#define MIR_CLIENT_SERVER_BUFFER_SEMANTICS_H |
1863 | + |
1864 | +#include "mir/optional_value.h" |
1865 | +#include "mir/frontend/buffer_stream_id.h" |
1866 | +#include "mir/geometry/size.h" |
1867 | +#include "mir_toolkit/common.h" |
1868 | +#include "mir/client_buffer.h" |
1869 | +#include "mir_protobuf.pb.h" |
1870 | + |
1871 | +#include <memory> |
1872 | + |
1873 | +namespace mir |
1874 | +{ |
1875 | +namespace client |
1876 | +{ |
1877 | + |
1878 | +//An internal interface useful in transitioning buffer exchange semantics based on |
1879 | +//the BufferStream response provided by the server |
1880 | +struct ServerBufferSemantics |
1881 | +{ |
1882 | + virtual void deposit(protobuf::Buffer const&, optional_value<geometry::Size>, MirPixelFormat) = 0; |
1883 | + virtual void set_buffer_cache_size(unsigned int) = 0; |
1884 | + virtual std::shared_ptr<ClientBuffer> current_buffer() = 0; |
1885 | + virtual uint32_t current_buffer_id() = 0; |
1886 | + virtual MirWaitHandle* submit(std::function<void()> const&, MirPixelFormat, int stream_id) = 0; |
1887 | + virtual void lost_connection() = 0; |
1888 | + virtual void set_size(geometry::Size) = 0; |
1889 | + virtual MirWaitHandle* set_scale(float, frontend::BufferStreamId) = 0; |
1890 | + virtual void set_interval(int interval) = 0; |
1891 | + virtual geometry::Size size() const = 0; |
1892 | + virtual ~ServerBufferSemantics() = default; |
1893 | + ServerBufferSemantics() = default; |
1894 | + ServerBufferSemantics(ServerBufferSemantics const&) = delete; |
1895 | + ServerBufferSemantics& operator=(ServerBufferSemantics const&) = delete; |
1896 | +}; |
1897 | + |
1898 | +} |
1899 | +} |
1900 | + |
1901 | +#endif /* MIR_CLIENT_SERVER_BUFFER_SEMANTICS_H */ |
1902 | |
1903 | === modified file 'src/client/symbols.map' |
1904 | --- src/client/symbols.map 2016-06-02 05:33:50 +0000 |
1905 | +++ src/client/symbols.map 2016-06-03 01:46:54 +0000 |
1906 | @@ -370,6 +370,7 @@ |
1907 | mir_connection_create_presentation_chain_sync; |
1908 | mir_presentation_chain_is_valid; |
1909 | mir_presentation_chain_get_error_message; |
1910 | + mir_create_egl_native_window; |
1911 | mir_connection_create_presentation_chain; |
1912 | mir_connection_allocate_buffer; |
1913 | mir_presentation_chain_submit_buffer; |
1914 | |
1915 | === modified file 'src/include/client/mir_toolkit/mir_presentation_chain.h' |
1916 | --- src/include/client/mir_toolkit/mir_presentation_chain.h 2016-06-02 05:33:50 +0000 |
1917 | +++ src/include/client/mir_toolkit/mir_presentation_chain.h 2016-06-03 01:46:54 +0000 |
1918 | @@ -29,6 +29,23 @@ |
1919 | #endif |
1920 | |
1921 | /** |
1922 | + * Extract an MirEGLNativeWindowType object from a given presentation chain. |
1923 | + * MirEGLNativeWindowType object that can be used in eglCreateWindowSurface() |
1924 | + * as native window. After this function is called, buffer management |
1925 | + * (allocation/deallocation/submission) of this presentation chain is done |
1926 | + * internally - clients should refrain from managing their buffers. |
1927 | + * |
1928 | + * \param [in] presentation_chain The presentation chain |
1929 | + * \param [in] width Native window width |
1930 | + * \param [in] height Native window height |
1931 | + * \param [in] pixel format Pixel format of native window |
1932 | + * \return MirEGLNativeWindowType object that can be used |
1933 | + * in eglCreateWindowSurface() as native window. |
1934 | + */ |
1935 | +MirEGLNativeWindowType mir_create_egl_native_window( |
1936 | + MirPresentationChain* presentation_chain, int width, int height, MirPixelFormat pixel_format); |
1937 | + |
1938 | +/** |
1939 | * Test for a valid presentation chain |
1940 | * |
1941 | * \param [in] presentation_chain The presentation chain |
1942 | |
1943 | === added file 'tests/unit-tests/client/stub_client_platform.h' |
1944 | --- tests/unit-tests/client/stub_client_platform.h 1970-01-01 00:00:00 +0000 |
1945 | +++ tests/unit-tests/client/stub_client_platform.h 2016-06-03 01:46:54 +0000 |
1946 | @@ -0,0 +1,79 @@ |
1947 | +/* |
1948 | + * Copyright © 2016 Canonical Ltd. |
1949 | + * |
1950 | + * This program is free software: you can redistribute it and/or modify it |
1951 | + * under the terms of the GNU General Public License version 3, |
1952 | + * as published by the Free Software Foundation. |
1953 | + * |
1954 | + * This program is distributed in the hope that it will be useful, |
1955 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1956 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1957 | + * GNU General Public License for more details. |
1958 | + * |
1959 | + * You should have received a copy of the GNU General Public License |
1960 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1961 | + * |
1962 | + * Authored by: Kevin DuBois <kevin.dubois@canonical.com> |
1963 | + */ |
1964 | + |
1965 | +#ifndef STUB_CLIENT_PLATFORM_H_ |
1966 | +#define STUB_CLIENT_PLATFORM_H_ |
1967 | + |
1968 | +#include "mir/client_platform.h" |
1969 | + |
1970 | +namespace |
1971 | +{ |
1972 | + |
1973 | +struct StubClientPlatform : public mir::client::ClientPlatform |
1974 | +{ |
1975 | + StubClientPlatform( |
1976 | + std::shared_ptr<mir::client::ClientBufferFactory> const& bf) |
1977 | + : buffer_factory(bf) |
1978 | + { |
1979 | + } |
1980 | + |
1981 | + MirPlatformType platform_type() const override |
1982 | + { |
1983 | + return MirPlatformType(); |
1984 | + } |
1985 | + |
1986 | + void populate(MirPlatformPackage& /* package */) const override |
1987 | + { |
1988 | + } |
1989 | + |
1990 | + std::shared_ptr<void> create_egl_native_window(mir::client::EGLNativeSurface * /* surface */) override |
1991 | + { |
1992 | + return mir::test::fake_shared(egl_native_window); |
1993 | + } |
1994 | + |
1995 | + std::shared_ptr<EGLNativeDisplayType> create_egl_native_display() override |
1996 | + { |
1997 | + return nullptr; |
1998 | + } |
1999 | + |
2000 | + MirNativeBuffer* convert_native_buffer(mir::graphics::NativeBuffer*) const override |
2001 | + { |
2002 | + return nullptr; |
2003 | + } |
2004 | + |
2005 | + std::shared_ptr<mir::client::ClientBufferFactory> create_buffer_factory() override |
2006 | + { |
2007 | + return buffer_factory; |
2008 | + } |
2009 | + |
2010 | + MirPlatformMessage* platform_operation(MirPlatformMessage const* /* request */) |
2011 | + { |
2012 | + return nullptr; |
2013 | + } |
2014 | + |
2015 | + MirPixelFormat get_egl_pixel_format(EGLDisplay, EGLConfig) const override |
2016 | + { |
2017 | + return mir_pixel_format_invalid; |
2018 | + } |
2019 | + |
2020 | + static EGLNativeWindowType egl_native_window; |
2021 | + std::shared_ptr<mir::client::ClientBufferFactory> const buffer_factory; |
2022 | +}; |
2023 | + |
2024 | +} |
2025 | +#endif /* STUB_CLIENT_PLATFORM_H_ */ |
2026 | |
2027 | === modified file 'tests/unit-tests/client/test_client_buffer_stream.cpp' |
2028 | --- tests/unit-tests/client/test_client_buffer_stream.cpp 2016-06-03 01:46:54 +0000 |
2029 | +++ tests/unit-tests/client/test_client_buffer_stream.cpp 2016-06-03 01:46:54 +0000 |
2030 | @@ -35,6 +35,8 @@ |
2031 | |
2032 | #include "mir_toolkit/mir_client_library.h" |
2033 | |
2034 | +#include "stub_client_platform.h" |
2035 | + |
2036 | #include <future> |
2037 | #include <atomic> |
2038 | |
2039 | @@ -57,49 +59,6 @@ |
2040 | arg1->set_error(message); |
2041 | } |
2042 | |
2043 | -struct StubClientPlatform : public mcl::ClientPlatform |
2044 | -{ |
2045 | - StubClientPlatform( |
2046 | - std::shared_ptr<mcl::ClientBufferFactory> const& bf) |
2047 | - : buffer_factory(bf) |
2048 | - { |
2049 | - } |
2050 | - MirPlatformType platform_type() const override |
2051 | - { |
2052 | - return MirPlatformType(); |
2053 | - } |
2054 | - void populate(MirPlatformPackage& /* package */) const override |
2055 | - { |
2056 | - } |
2057 | - std::shared_ptr<void> create_egl_native_window(mcl::EGLNativeSurface * /* surface */) override |
2058 | - { |
2059 | - return mt::fake_shared(egl_native_window); |
2060 | - } |
2061 | - std::shared_ptr<EGLNativeDisplayType> create_egl_native_display() override |
2062 | - { |
2063 | - return nullptr; |
2064 | - } |
2065 | - MirNativeBuffer* convert_native_buffer(mg::NativeBuffer*) const override |
2066 | - { |
2067 | - return nullptr; |
2068 | - } |
2069 | - |
2070 | - std::shared_ptr<mcl::ClientBufferFactory> create_buffer_factory() override |
2071 | - { |
2072 | - return buffer_factory; |
2073 | - } |
2074 | - MirPlatformMessage* platform_operation(MirPlatformMessage const* /* request */) |
2075 | - { |
2076 | - return nullptr; |
2077 | - } |
2078 | - MirPixelFormat get_egl_pixel_format(EGLDisplay, EGLConfig) const override |
2079 | - { |
2080 | - return mir_pixel_format_invalid; |
2081 | - } |
2082 | - static EGLNativeWindowType egl_native_window; |
2083 | - std::shared_ptr<mcl::ClientBufferFactory> const buffer_factory; |
2084 | -}; |
2085 | - |
2086 | struct MockPerfReport : public mcl::PerfReport |
2087 | { |
2088 | MOCK_METHOD1(name_surface, void(char const*)); |
2089 | |
2090 | === modified file 'tests/unit-tests/client/test_connection_resource_map.cpp' |
2091 | --- tests/unit-tests/client/test_connection_resource_map.cpp 2016-06-02 05:33:50 +0000 |
2092 | +++ tests/unit-tests/client/test_connection_resource_map.cpp 2016-06-03 01:46:54 +0000 |
2093 | @@ -42,7 +42,7 @@ |
2094 | std::make_shared<mcl::Buffer>(buffer_cb, nullptr, 0, nullptr, nullptr, mir_buffer_usage_software) }; |
2095 | mtd::MockProtobufServer mock_server; |
2096 | std::shared_ptr<mcl::PresentationChain> chain{ std::make_shared<mcl::PresentationChain>( |
2097 | - nullptr, 0, mock_server, nullptr, nullptr) }; |
2098 | + nullptr, 0, mock_server, nullptr, nullptr, nullptr, std::shared_ptr<mcl::SurfaceMap>(nullptr), 0) }; |
2099 | |
2100 | mf::SurfaceId const surface_id{43}; |
2101 | mf::BufferStreamId const stream_id{43}; |
2102 | |
2103 | === modified file 'tests/unit-tests/client/test_presentation_chain.cpp' |
2104 | --- tests/unit-tests/client/test_presentation_chain.cpp 2016-06-02 05:33:50 +0000 |
2105 | +++ tests/unit-tests/client/test_presentation_chain.cpp 2016-06-03 01:46:54 +0000 |
2106 | @@ -21,13 +21,18 @@ |
2107 | #include "mir/test/doubles/mock_client_buffer.h" |
2108 | #include "mir/test/fake_shared.h" |
2109 | #include "src/client/presentation_chain.h" |
2110 | +#include "src/client/connection_surface_map.h" |
2111 | #include "src/client/buffer_factory.h" |
2112 | #include "mir/client_buffer_factory.h" |
2113 | +#include "stub_client_platform.h" |
2114 | |
2115 | #include <mutex> |
2116 | #include <condition_variable> |
2117 | #include <gtest/gtest.h> |
2118 | + |
2119 | using namespace testing; |
2120 | + |
2121 | +namespace mt = mir::test; |
2122 | namespace mtd = mir::test::doubles; |
2123 | namespace geom = mir::geometry; |
2124 | namespace mcl = mir::client; |
2125 | @@ -50,11 +55,15 @@ |
2126 | geom::Size size {100, 200}; |
2127 | MirPixelFormat format = mir_pixel_format_abgr_8888; |
2128 | MirBufferUsage usage = mir_buffer_usage_software; |
2129 | - mtd::MockProtobufServer mock_server; |
2130 | + NiceMock<mtd::MockProtobufServer> mock_server; |
2131 | int buffer_id {4312}; |
2132 | mp::Buffer ipc_buf; |
2133 | std::shared_ptr<mtd::StubClientBuffer> client_buffer = std::make_shared<mtd::StubClientBuffer>( |
2134 | std::make_shared<MirBufferPackage>(), size, format); |
2135 | + std::shared_ptr<mcl::ConnectionSurfaceMap> map{std::make_shared<mcl::ConnectionSurfaceMap>()}; |
2136 | + mtd::StubClientBufferFactory stub_factory; |
2137 | + std::shared_ptr<mcl::BufferFactory> factory{std::make_shared<mcl::BufferFactory>()}; |
2138 | + size_t nbuffers{3}; |
2139 | }; |
2140 | |
2141 | MATCHER_P(BufferRequestMatches, val, "") |
2142 | @@ -65,6 +74,9 @@ |
2143 | arg->buffer().buffer_id() == val.buffer().buffer_id()); |
2144 | } |
2145 | |
2146 | +EGLNativeWindowType StubClientPlatform::egl_native_window{ |
2147 | + reinterpret_cast<EGLNativeWindowType>(&StubClientPlatform::egl_native_window)}; |
2148 | + |
2149 | void buffer_callback(MirBuffer*, void*) |
2150 | { |
2151 | } |
2152 | @@ -75,8 +87,11 @@ |
2153 | { |
2154 | mcl::PresentationChain chain( |
2155 | connection, rpc_id, mock_server, |
2156 | + std::make_shared<StubClientPlatform>(mt::fake_shared(stub_factory)), |
2157 | std::make_shared<mtd::StubClientBufferFactory>(), |
2158 | - std::make_shared<mcl::BufferFactory>()); |
2159 | + factory, |
2160 | + map, |
2161 | + nbuffers); |
2162 | EXPECT_THAT(chain.connection(), Eq(connection)); |
2163 | } |
2164 | |
2165 | @@ -84,8 +99,11 @@ |
2166 | { |
2167 | mcl::PresentationChain chain( |
2168 | connection, rpc_id, mock_server, |
2169 | + std::make_shared<StubClientPlatform>(mt::fake_shared(stub_factory)), |
2170 | std::make_shared<mtd::StubClientBufferFactory>(), |
2171 | - std::make_shared<mcl::BufferFactory>()); |
2172 | + factory, |
2173 | + map, |
2174 | + nbuffers); |
2175 | EXPECT_THAT(chain.rpc_id(), Eq(rpc_id)); |
2176 | } |
2177 | |
2178 | @@ -101,8 +119,11 @@ |
2179 | mcl::Buffer buffer(buffer_callback, nullptr, buffer_id, client_buffer, nullptr, mir_buffer_usage_software); |
2180 | mcl::PresentationChain chain( |
2181 | connection, rpc_id, mock_server, |
2182 | + std::make_shared<StubClientPlatform>(mt::fake_shared(stub_factory)), |
2183 | std::make_shared<mtd::StubClientBufferFactory>(), |
2184 | - std::make_shared<mcl::BufferFactory>()); |
2185 | + factory, |
2186 | + map, |
2187 | + nbuffers); |
2188 | |
2189 | buffer.received(); |
2190 | chain.submit_buffer(reinterpret_cast<MirBuffer*>(&buffer)); |
2191 | @@ -116,8 +137,11 @@ |
2192 | mcl::Buffer buffer(buffer_callback, nullptr, buffer_id, client_buffer, nullptr, mir_buffer_usage_software); |
2193 | mcl::PresentationChain chain( |
2194 | connection, rpc_id, mock_server, |
2195 | + std::make_shared<StubClientPlatform>(mt::fake_shared(stub_factory)), |
2196 | std::make_shared<mtd::StubClientBufferFactory>(), |
2197 | - std::make_shared<mcl::BufferFactory>()); |
2198 | + factory, |
2199 | + map, |
2200 | + nbuffers); |
2201 | |
2202 | buffer.received(); |
2203 | chain.submit_buffer(reinterpret_cast<MirBuffer*>(&buffer)); |
2204 | @@ -126,3 +150,81 @@ |
2205 | chain.submit_buffer(reinterpret_cast<MirBuffer*>(&buffer)); |
2206 | }, std::logic_error); |
2207 | } |
2208 | + |
2209 | +TEST_F(PresentationChain, gets_egl_native_window) |
2210 | +{ |
2211 | + int const width = 73; |
2212 | + int const height = 32; |
2213 | + MirPixelFormat const format = mir_pixel_format_argb_8888; |
2214 | + |
2215 | + mcl::PresentationChain chain( |
2216 | + connection, rpc_id, mock_server, |
2217 | + std::make_shared<StubClientPlatform>(mt::fake_shared(stub_factory)), |
2218 | + std::make_shared<mtd::StubClientBufferFactory>(), |
2219 | + factory, |
2220 | + map, |
2221 | + nbuffers); |
2222 | + |
2223 | + EXPECT_EQ(StubClientPlatform::egl_native_window, chain.egl_native_window(geom::Size{width, height}, format)); |
2224 | +} |
2225 | + |
2226 | +TEST_F(PresentationChain, returns_correct_parameters) |
2227 | +{ |
2228 | + int const width = 73; |
2229 | + int const height = 32; |
2230 | + MirPixelFormat const format = mir_pixel_format_argb_8888; |
2231 | + MirBufferUsage const usage = mir_buffer_usage_hardware; |
2232 | + MirSurfaceParameters params; |
2233 | + |
2234 | + mcl::PresentationChain chain( |
2235 | + connection, rpc_id, mock_server, |
2236 | + std::make_shared<StubClientPlatform>(mt::fake_shared(stub_factory)), |
2237 | + std::make_shared<mtd::StubClientBufferFactory>(), |
2238 | + factory, |
2239 | + map, |
2240 | + nbuffers); |
2241 | + chain.egl_native_window(geom::Size{width, height}, format); |
2242 | + |
2243 | + EXPECT_NO_THROW(params = chain.get_parameters()); |
2244 | + |
2245 | + EXPECT_STREQ("", params.name); |
2246 | + EXPECT_EQ(width, params.width); |
2247 | + EXPECT_EQ(height, params.height); |
2248 | + EXPECT_EQ(format, params.pixel_format); |
2249 | + EXPECT_EQ(usage, params.buffer_usage); |
2250 | +} |
2251 | + |
2252 | +TEST_F(PresentationChain, EGLNativeSurface_functions_throw_when_egl_native_window_not_called) |
2253 | +{ |
2254 | + mcl::PresentationChain chain( |
2255 | + connection, rpc_id, mock_server, |
2256 | + std::make_shared<StubClientPlatform>(mt::fake_shared(stub_factory)), |
2257 | + std::make_shared<mtd::StubClientBufferFactory>(), |
2258 | + factory, |
2259 | + map, |
2260 | + nbuffers); |
2261 | + |
2262 | + ASSERT_THROW(chain.get_parameters(), std::runtime_error); |
2263 | +} |
2264 | + |
2265 | +TEST_F(PresentationChain, submission_throws_in_EGL_mode) |
2266 | +{ |
2267 | + int const width = 73; |
2268 | + int const height = 32; |
2269 | + MirPixelFormat const format = mir_pixel_format_argb_8888; |
2270 | + |
2271 | + mcl::PresentationChain chain( |
2272 | + connection, rpc_id, mock_server, |
2273 | + std::make_shared<StubClientPlatform>(mt::fake_shared(stub_factory)), |
2274 | + std::make_shared<mtd::StubClientBufferFactory>(), |
2275 | + factory, |
2276 | + map, |
2277 | + nbuffers); |
2278 | + |
2279 | + EXPECT_EQ(StubClientPlatform::egl_native_window, chain.egl_native_window(geom::Size{width, height}, format)); |
2280 | + |
2281 | + mcl::Buffer buffer(buffer_callback, nullptr, buffer_id, client_buffer, nullptr, mir_buffer_usage_software); |
2282 | + buffer.received(); |
2283 | + |
2284 | + ASSERT_THROW(chain.submit_buffer(reinterpret_cast<MirBuffer*>(&buffer)), std::runtime_error); |
2285 | +} |
FAILED: Continuous integration, rev:3528 /mir-jenkins. ubuntu. com/job/ mir-ci/ 1075/ /mir-jenkins. ubuntu. com/job/ build-mir/ 1187/console /mir-jenkins. ubuntu. com/job/ build-0- fetch/1237 /mir-jenkins. ubuntu. com/job/ build-1- sourcepkg/ release= vivid+overlay/ 1228 /mir-jenkins. ubuntu. com/job/ build-1- sourcepkg/ release= xenial/ 1228 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= clang,platform= mesa,release= vivid+overlay/ 1197 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= clang,platform= mesa,release= vivid+overlay/ 1197/artifact/ output/ *zip*/output. zip /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= gcc,platform= mesa,release= xenial/ 1197 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= gcc,platform= mesa,release= xenial/ 1197/artifact/ output/ *zip*/output. zip /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= cross-armhf, compiler= gcc,platform= android, release= vivid+overlay/ 1197/console /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= cross-armhf, compiler= gcc,platform= android, release= vivid+overlay/ 1197/artifact/ output/ *zip*/output. zip /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= i386,compiler= gcc,platform= android, release= vivid+overlay/ 1197 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= i386,compiler= gcc,platform= android, release= vivid+overlay/ 1197/artifact/ output/ *zip*/output. zip /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= i386,compiler= gcc,platform= mesa,release= xenial/ 1197/console
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
Click here to trigger a rebuild: /mir-jenkins. ubuntu. com/job/ mir-ci/ 1075/rebuild
https:/