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