Merge lp:~raof/mir/provide-event-fd into lp:mir
- provide-event-fd
- Merge into development-branch
Status: | Work in progress |
---|---|
Proposed branch: | lp:~raof/mir/provide-event-fd |
Merge into: | lp:mir |
Prerequisite: | lp:~raof/mir/make-input-dispatcher-a-dispatchable |
Diff against target: |
7460 lines (+4248/-373) (has conflicts) 87 files modified
benchmarks/benchmark_multiplexing_dispatchable.cpp (+1/-0) debian/control (+1/-0) examples/chain_jumping_buffers.c (+6/-0) examples/prerendered_frames.c (+5/-0) examples/render_surface.cpp (+20/-4) include/client/mir_toolkit/mir_connection.h (+70/-0) include/client/mir_toolkit/mir_wait.h (+1/-0) include/client/mir_toolkit/rs/mir_render_surface.h (+69/-5) include/common/mir/dispatch/threaded_dispatcher.h.moved (+75/-0) include/test/mir/test/validity_matchers.h (+8/-0) playground/egldiamond_render_surface.c (+5/-0) playground/mir_egl_platform_shim.c (+9/-0) src/client/CMakeLists.txt (+9/-0) src/client/buffer_factory.cpp (+11/-1) src/client/buffer_stream.cpp (+146/-38) src/client/buffer_stream.h (+27/-3) src/client/buffer_stream_configuration.cpp (+8/-0) src/client/buffer_stream_configuration.h (+1/-0) src/client/buffer_vault.cpp (+22/-5) src/client/client_buffer_stream_factory.h.THIS (+66/-0) src/client/connection_configuration.h (+11/-0) src/client/connection_surface_map.cpp (+53/-1) src/client/connection_surface_map.h (+32/-0) src/client/default_client_buffer_stream_factory.cpp.THIS (+87/-0) src/client/default_client_buffer_stream_factory.h.THIS (+70/-0) src/client/default_connection_configuration.cpp (+15/-2) src/client/default_connection_configuration.h (+2/-0) src/client/error_render_surface.cpp (+1/-4) src/client/error_render_surface.h (+6/-3) src/client/mir_buffer_stream_api.cpp (+29/-14) src/client/mir_connection.cpp (+194/-50) src/client/mir_connection.h (+37/-11) src/client/mir_connection_api.cpp (+159/-0) src/client/mir_prompt_session_api.cpp (+13/-0) src/client/mir_render_surface_api.cpp (+104/-4) src/client/mir_screencast.cpp (+13/-2) src/client/mir_screencast.h (+2/-1) src/client/mir_screencast_api.cpp (+20/-3) src/client/mir_surface.cpp (+30/-2) src/client/mir_surface.h (+5/-2) src/client/mir_surface_api.cpp (+25/-0) src/client/mir_wait_api.cpp (+9/-0) src/client/no_tls_future-inl.h (+1/-0) src/client/render_surface.cpp (+34/-14) src/client/render_surface.h (+6/-3) src/client/rpc/make_rpc_channel.h (+1/-0) src/client/rpc/mir_basic_rpc_channel.h (+8/-0) src/client/rpc/mir_protobuf_rpc_channel.cpp (+10/-1) src/client/rpc/mir_protobuf_rpc_channel.h (+3/-3) src/client/symbols.map (+21/-0) src/client/synchronous_helper.cpp (+33/-0) src/client/synchronous_helper.h (+160/-0) src/common/dispatch/threaded_dispatcher.cpp.moved (+294/-0) src/include/client/mir/mir_render_surface.h (+6/-3) src/server/scene/mediating_display_changer.cpp (+1/-1) tests/acceptance-tests/CMakeLists.txt (+8/-0) tests/acceptance-tests/test_client_library.cpp (+494/-0) tests/acceptance-tests/test_client_surfaces.cpp (+40/-0) tests/acceptance-tests/test_render_surface.cpp (+235/-20) tests/acceptance-tests/test_server_shutdown.cpp (+1/-1) tests/include/mir/test/doubles/mock_client_buffer_stream_factory.h.THIS (+59/-0) tests/include/mir/test/doubles/mock_mir_buffer_stream.h (+1/-0) tests/include/mir/test/doubles/stub_buffer_stream_factory.h (+18/-2) tests/include/mir/test/doubles/stub_client_buffer_stream_factory.h.THIS (+66/-0) tests/integration-tests/test_buffer_scheduling.cpp (+3/-1) tests/integration-tests/test_surfaceloop.cpp (+60/-35) tests/integration-tests/test_swapinterval.cpp (+2/-2) tests/mir_test/CMakeLists.txt (+5/-1) tests/mir_test/validity_matchers.cpp (+31/-0) tests/mir_test_doubles/stub_buffer.cpp.THIS (+39/-0) tests/mir_test_doubles/test_protobuf_client.cpp (+2/-1) tests/mir_test_framework/CMakeLists.txt (+1/-0) tests/mir_test_framework/udev_environment.cpp (+12/-4) tests/unit-tests/client/test_buffer_vault.cpp (+2/-1) tests/unit-tests/client/test_client_buffer_stream.cpp (+158/-82) tests/unit-tests/client/test_client_mir_surface.cpp (+22/-0) tests/unit-tests/client/test_connection_resource_map.cpp (+71/-5) tests/unit-tests/client/test_mir_connection.cpp (+206/-7) tests/unit-tests/client/test_mir_render_surface.cpp (+182/-20) tests/unit-tests/compositor/test_stream.cpp (+1/-1) tests/unit-tests/dispatch/CMakeLists.txt (+1/-0) tests/unit-tests/dispatch/test_multiplexing_dispatchable.cpp (+7/-8) tests/unit-tests/dispatch/test_threaded_dispatcher.cpp.moved (+403/-0) tests/unit-tests/frontend/stress_protobuf_communicator.cpp (+4/-1) tests/unit-tests/scene/test_application_session.cpp (+3/-1) tests/unit-tests/scene/test_surface_stack.cpp (+11/-0) tools/valgrind_suppressions_generic (+45/-0) Text conflict in examples/chain_jumping_buffers.c Text conflict in examples/prerendered_frames.c Text conflict in examples/render_surface.cpp Text conflict in include/client/mir_toolkit/rs/mir_render_surface.h Text conflict in playground/egldiamond_render_surface.c Text conflict in playground/mir_egl_platform_shim.c Text conflict in src/client/CMakeLists.txt Text conflict in src/client/buffer_stream.cpp Text conflict in src/client/buffer_stream.h Text conflict in src/client/connection_surface_map.cpp Text conflict in src/client/connection_surface_map.h Text conflict in src/client/mir_buffer_stream_api.cpp Text conflict in src/client/mir_connection.cpp Text conflict in src/client/mir_connection_api.cpp Text conflict in src/client/mir_prompt_session_api.cpp Text conflict in src/client/mir_render_surface_api.cpp Text conflict in src/client/mir_screencast.cpp Text conflict in src/client/mir_surface.cpp Text conflict in src/client/mir_surface.h Text conflict in src/client/mir_surface_api.cpp Text conflict in src/client/rpc/mir_basic_rpc_channel.h Text conflict in src/client/rpc/mir_protobuf_rpc_channel.cpp Text conflict in src/client/symbols.map Text conflict in tests/acceptance-tests/CMakeLists.txt Text conflict in tests/acceptance-tests/test_client_library.cpp Text conflict in tests/acceptance-tests/test_client_surfaces.cpp Text conflict in tests/acceptance-tests/test_render_surface.cpp Text conflict in tests/include/mir/test/doubles/stub_buffer_stream_factory.h Text conflict in tests/integration-tests/test_surfaceloop.cpp Text conflict in tests/unit-tests/client/test_client_buffer_stream.cpp Text conflict in tests/unit-tests/client/test_client_mir_surface.cpp Text conflict in tests/unit-tests/client/test_connection_resource_map.cpp Text conflict in tests/unit-tests/client/test_mir_connection.cpp Text conflict in tests/unit-tests/client/test_mir_render_surface.cpp Text conflict in tests/unit-tests/scene/test_surface_stack.cpp |
To merge this branch: | bzr merge lp:~raof/mir/provide-event-fd |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot (community) | continuous-integration | Needs Fixing | |
Alexandros Frantzis (community) | Needs Fixing | ||
Andreas Pokorny (community) | Approve | ||
Robert Carr (community) | Approve | ||
Kevin DuBois (community) | Approve | ||
Review via email: mp+247794@code.launchpad.net |
Commit message
Provide a mechanism for manual dispatch of client events.
A client can create a manually dispatched MirConnection by mir_connect_
Description of the change
The last, client-visible component of eventloop-
The relevant client API bits are mir_connect_
This mostly preserves the current behaviour for automatic, threaded dispatch. The one difference is that there are now no longer dedicated threads for surfaces' input loops; instead there is now one thread per surface with input plus one for RPC that together dispatch whatever events may happen.
PS Jenkins bot (ps-jenkins) wrote : | # |
Kevin DuBois (kdub) wrote : | # |
int mir_connection_
It seems more important what the fd is for, so I'd rather the fn say something about what the fd does... maybe:
int mir_connection_
201 + thread_local static bool running;
Nothing wrong here, but we still haven't properly sorted out TLS with hybris. We'd probably be a bit more robust if we still avoid using TLS.
704 + if (pipe2(pipefds, O_NONBLOCK) < 0)
O_CLOEXEC?
Chris Halse Rogers (raof) wrote : | # |
On Thu, Jan 29, 2015 at 1:18 AM, Kevin DuBois
<email address hidden> wrote:
> Review: Needs Fixing
>
> int mir_connection_
> It seems more important what the fd is for, so I'd rather the fn say
> something about what the fd does... maybe:
> int mir_connection_
Seems reasonable, I'll use that naming.
>
>
> 201 + thread_local static bool running;
> Nothing wrong here, but we still haven't properly sorted out TLS with
> hybris. We'd probably be a bit more robust if we still avoid using
> TLS.
Boo. And it was sooooo elegant.
I'll rework this to not need TLS.
>
> 704 + if (pipe2(pipefds, O_NONBLOCK) < 0)
> O_CLOEXEC?
While we're at it, yes.
Chris Halse Rogers (raof) wrote : | # |
Harumph.
So, this adds tests to TestClientLibrary that require umockdev's evemu replay functionality. I guess I'll need to (a) modify the test runner to call through umockdev-run, (b) ensure that the recordings get installed in the packages, and (c) ensure that the tests can *find* them.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2331
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
FAILURE: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Kevin DuBois (kdub) wrote : | # |
looks good to me, although perhaps some clients might disagree with:
757 + // If the client is entirely unresponsive for a whole minute, it deserves to die.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2337
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2338
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2339
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:2340
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Robert Carr (robertcarr) wrote : | # |
I really like the way this turned out :)
A few nits:
+TEST_F(
I think its worth refactoring this and the following test. If you merged the TestData and test up to SurfaceCreation in to a fixture it would be possible to then split the sections of the test without duplicating code. Then the next test could not have to deal with surface states and umockdev recordings in the same test.
1888 and elsewhere + auto connection = std::make_
You can keep connection in the fixture and then inherit from the fixture with
MirConnectionAu
Robert Carr (robertcarr) wrote : | # |
2 small needs fixing:
The 1 second timeouts are going to fail in ARMHF valgrind.
1499 + GError* err = nullptr;
Here and at 1511 please use g_error_free (I know a leak is unlikely to matter here but its worth using the API correctly I think)
Robert Carr (robertcarr) wrote : | # |
PINGGGGGGGGGGGG
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:2346
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Chris Halse Rogers (raof) wrote : | # |
PIIIIING responded to :)
Andreas Pokorny (andreas-pokorny) wrote : | # |
A call to mir::set_
What about exceptions that reach the dispatch_loop? Do we need something like mir_terminate_
Looks good otherwise
Andreas Pokorny (andreas-pokorny) wrote : | # |
> A call to mir::set_
Could be a constructor parameter to ThreadedDispatc
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2349
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Andreas Pokorny (andreas-pokorny) wrote : | # |
lgtm as soon as jenkins agrees.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:2350
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Autolanding.
More details in the following jenkins job:
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Chris Halse Rogers (raof) wrote : | # |
Retrigger CI now that we've got shiny new log output for the failed test.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Autolanding.
More details in the following jenkins job:
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
- 2351. By Chris Halse Rogers
-
Switch manual dispatch tests over to an eventloop thread.
This still tests that the callbacks are dispatched on the thread that called dispatch(),
but doesn't rely on implementation details like how many times you'll need to call
dispatch() after each request in order to get it processed, and is less prone to possible
races where fd readability races the while(fd_is_readable( )) loop.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2351
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 2352. By Chris Halse Rogers
-
Merge trunk
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2352
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Alexandros Frantzis (afrantzis) wrote : | # |
267 + dispatcher{
Why not std::make_shared?
286 + if (eventloop) abort();
It would be helpful to the poor users if we printed an informative error message before we abort.
755 + std::thread::id terminate_
I think there is a potential race here:
T1: calls terminate_
A thread terminates, sets terminating_
Another thread terminates, sets terminating_
T1 wakes up, finds a valid terminating_
T2 wakes up, finds a cleared terminating_
- 2353. By Chris Halse Rogers
-
Add timeout to EventDispatchThread
- 2354. By Chris Halse Rogers
-
Resolve race in terminate_
one_thread. If two threads called terminate_
one_thread simultaneously it was possible for
both threadpool threads to unregister before either terminate_one_thread picked the
terminating_thread_ mutex lock up again. In this case the second threadpool thread would overwrite terminating_
thread_ id, and the
second terminate_one_thread call would timeout. This is fundamentally a typical producer/consumer situation; resolve it by having terminating
threads write to a queue of ids, and terminate_one_thread pull from that queue. - 2355. By Chris Halse Rogers
-
Switch ThreadExiter over to an eventfd.
We don't actually need a pipe; an eventfd is lighter for just handling notifications.
- 2356. By Chris Halse Rogers
-
Fix handles_
events_ in_parent_ thread test. We need to post a buffer to the surface in order for it to be a vaild focus target!
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2356
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 2357. By Chris Halse Rogers
-
Merge trunk
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2357
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 2358. By Chris Halse Rogers
-
Merge trunk. MOAR CONFLICTS!
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2358
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 2359. By Chris Halse Rogers
-
Merge trunk
- 2360. By Chris Halse Rogers
-
Fix race in dispatches_
multiple_ dispatchees_ simultaneously
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2360
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
FAILURE: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 2361. By Chris Halse Rogers
-
Merge trunk
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2360
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2361
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
FAILURE: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2362
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
FAILURE: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2364
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Alan Griffiths (alan-griffiths) wrote : | # |
2850+ auto dispatchable = std::make_
2851+ {
2852+ static std::atomic<int> dispatch_count{0};
2853+ char buffer[80] = {0};
2854+ pthread_
2855+ EXPECT_THAT(buffer, StartsWith(
2856+
2857+ if (++dispatch_count == threadcount)
2858+ {
2859+ dispatched-
2860+ }
2861+ else
2862+ {
2863+ dispatched-
2864+ }
2865+ });
I'm not convinced by the massive indents that this style causes. (Nor the multi-line diffs a simple change like "auto dispatchable" => "auto const dispatchable" would imply.)
Alexandros Frantzis (afrantzis) wrote : | # |
286 + if (eventloop) abort();
We should print out an error message before we abort so that the users have some clue of what they did wrong.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2366
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
FAILURE: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Chris Halse Rogers (raof) wrote : | # |
Oh ho ho!
While cleaning up the dispatch tests I've noticed that mir_connection_
Ryan *will* be pleased that I have to fix that case first!
- 2362. By Chris Halse Rogers
-
Merge trunk
- 2363. By Chris Halse Rogers
-
ClientLibrary dispatch tests: release the MirConnection from the dispatch thread.
This prevents us from accessing a freed MirConnection.
- 2364. By Chris Halse Rogers
-
Add acceptance test for async/sync call interaction with manual dispatch.
- 2365. By Chris Halse Rogers
-
Use mir::require for MirConnection:
:dispatch( ) precondition - 2366. By Chris Halse Rogers
-
make_client_
protobuf_ tests_match_ naming_ scheme - 2367. By Chris Halse Rogers
-
Merge trunk
- 2368. By Chris Halse Rogers
-
Improve MirProtobufRpcC
hanneltests. Rather than having the mock StreamTransport manually notifying until all
data is read (somewhat defeating the purpose of the “does it read all the
data” test), have the mock StreamTransport properly implement Dispatchable
and use MirProtobufRpcChannel' s Dispatchable interface to drive things. - 2369. By Chris Halse Rogers
-
Merge prereq: ActionQueue
- 2370. By Chris Halse Rogers
-
Add an out-of-order processing mode to MirProtobufRpcC
hannel. This lets a consumer wait on the result of a particular call, delaying other message
processing until it has completed.This is required for proper *_sync handling in eventloop-driven dispatch mode.
- 2371. By Chris Halse Rogers
-
Fix mir_connection_
release with manual dispatch - 2372. By Chris Halse Rogers
-
Hook up process_
next_request_ first to MirConnection - 2373. By Chris Halse Rogers
-
Add mir_wait_
handle_ ready to client API - 2374. By Chris Halse Rogers
-
Pump the eventloop from the main test body.
This makes it possible to mix synchronous and asynchronous calls in the test;
otherwise the synchonous calls get done on the main thread, and the asynchonous
calls on the eventloop thread. - 2375. By Chris Halse Rogers
-
Move reply parsing out of PendingCallCache and into ProtobufRpc.
This lets us do all the reply processing in one place, leaving the
PendingCallCache to just handle ID lookup, storage, and final completion
dispatch. - 2376. By Chris Halse Rogers
-
Make MirBasicRpcChannel the lowest-
common- denominator type. Rather than dynamic_cast<>ing in multiple places, just return a MirBasicRpcChannel
from ConnectionConfiguration and ensure that MirBasicRpcChannel provides all the
interfaces the code needs. - 2377. By Chris Halse Rogers
-
Add a way to get the MirConnection associated with a BufferStream.
This is necessary for synchonous calls on manually-dispatched MirConnections
- 2378. By Chris Halse Rogers
-
Add a way to get the MirConnection associated with a MirSurface
- 2379. By Chris Halse Rogers
-
We treat MirBufferStream as a ClientBufferStream internally - make sure the pointers we return *are* ClientBufferStreams
- 2380. By Chris Halse Rogers
-
Enable getting a MirConnection out of a MirScreencast
- 2381. By Chris Halse Rogers
-
Add helper infrastructure for making synchronous RPC calls
- 2382. By Chris Halse Rogers
-
Use make_synchronou
s_call helper for all synchronous RPC calls - 2383. By Chris Halse Rogers
-
Minor improvements to synchronous helper
- 2384. By Chris Halse Rogers
-
Initialise ProtobufRpcChan
nel::prioritise _next_request. Thanks, valgrind.
- 2385. By Chris Halse Rogers
-
Don't call a synchronous method from a manually-dispatched async callback.
This fails for... some reason. Don't know at the moment.
- 2386. By Chris Halse Rogers
-
Free the surface_spec in ClientLibrary test.
Now doesn't leak!
- 2387. By Chris Halse Rogers
-
Add valgrind suppressions for GDBus bollocks.
- 2388. By Chris Halse Rogers
-
Merge trunk.
Lots and lots of changes, and the test-suite now fails due to NBS, but
commit this so that there's a stable base to fix the test-suite on. - 2389. By Chris Halse Rogers
-
Merge prerequisite
- 2390. By Chris Halse Rogers
-
Set connection field of MirScreencast error-objects.
The synchonous dispatch helper requires the MirConnection to be valid.
- 2391. By Chris Halse Rogers
-
Update tests; everything now passes.
Mostly. Still have crashes where *_release_sync race with event delivery on the released object.
- 2392. By Chris Halse Rogers
-
Remove superfluous threads in tests.
These mt::AutoJoinThr
ead()s were immediately being destroyed - and so, thread.join()ed - so
they only served to obfuscate the callstack. - 2393. By Chris Halse Rogers
-
Add mir_connect_
with_manual_ dispatch_ sync. It's easy, it's plausibly useful, and it makes the tests easier
- 2394. By Chris Halse Rogers
-
Merge trunk
- 2395. By Chris Halse Rogers
-
Revert no-hidden-
RPC-in- bufferstream. This turns out to be surprisingly hard, and I can work around it.
- 2396. By Chris Halse Rogers
-
Merge trunk
- 2397. By Chris Halse Rogers
-
Revert the no-hidden-
BufferStream- RPC reversion. Turns out I *can* make this work.
- 2398. By Chris Halse Rogers
-
Merge in new bufferstream-
no-hidden- RPC - 2399. By Chris Halse Rogers
-
Merge trunk, resolving conflicts but not testsuite failures
- 2400. By Chris Halse Rogers
-
Merge BufferStream simplification branch
- 2401. By Chris Halse Rogers
-
Merge NoTLSFuture<
T>::detach( ) - 2402. By Chris Halse Rogers
-
Merge prerequisite, resolving conflicts
Unmerged revisions
- 2402. By Chris Halse Rogers
-
Merge prerequisite, resolving conflicts
- 2401. By Chris Halse Rogers
-
Merge NoTLSFuture<
T>::detach( ) - 2400. By Chris Halse Rogers
-
Merge BufferStream simplification branch
- 2399. By Chris Halse Rogers
-
Merge trunk, resolving conflicts but not testsuite failures
- 2398. By Chris Halse Rogers
-
Merge in new bufferstream-
no-hidden- RPC - 2397. By Chris Halse Rogers
-
Revert the no-hidden-
BufferStream- RPC reversion. Turns out I *can* make this work.
- 2396. By Chris Halse Rogers
-
Merge trunk
- 2395. By Chris Halse Rogers
-
Revert no-hidden-
RPC-in- bufferstream. This turns out to be surprisingly hard, and I can work around it.
- 2394. By Chris Halse Rogers
-
Merge trunk
- 2393. By Chris Halse Rogers
-
Add mir_connect_
with_manual_ dispatch_ sync. It's easy, it's plausibly useful, and it makes the tests easier
Preview Diff
1 | === modified file 'benchmarks/benchmark_multiplexing_dispatchable.cpp' |
2 | --- benchmarks/benchmark_multiplexing_dispatchable.cpp 2015-06-17 05:20:42 +0000 |
3 | +++ benchmarks/benchmark_multiplexing_dispatchable.cpp 2017-03-28 00:17:49 +0000 |
4 | @@ -19,6 +19,7 @@ |
5 | #include "mir/dispatch/multiplexing_dispatchable.h" |
6 | |
7 | #include <iostream> |
8 | +#include <thread> |
9 | #include <vector> |
10 | #include <memory> |
11 | #include <chrono> |
12 | |
13 | === modified file 'debian/control' |
14 | --- debian/control 2017-03-22 23:38:59 +0000 |
15 | +++ debian/control 2017-03-28 00:17:49 +0000 |
16 | @@ -288,6 +288,7 @@ |
17 | Pre-Depends: ${misc:Pre-Depends} |
18 | Depends: ${misc:Depends}, |
19 | ${shlibs:Depends}, |
20 | + umockdev, |
21 | Recommends: mir-demos, |
22 | Description: Display Server for Ubuntu - stress tests and other test tools |
23 | Mir is a display server running on linux systems, with a focus on efficiency, |
24 | |
25 | === modified file 'examples/chain_jumping_buffers.c' |
26 | --- examples/chain_jumping_buffers.c 2017-03-10 19:47:57 +0000 |
27 | +++ examples/chain_jumping_buffers.c 2017-03-28 00:17:49 +0000 |
28 | @@ -268,8 +268,14 @@ |
29 | for (unsigned int i = 0u; i < num_buffers; i++) |
30 | mir_buffer_release(buffer_available[i].buffer); |
31 | for (unsigned int i = 0u; i < num_chains; i++) |
32 | +<<<<<<< TREE |
33 | mir_render_surface_release(render_surface[i]); |
34 | mir_window_release_sync(window); |
35 | +======= |
36 | + mir_render_surface_release_sync(render_surface[i]); |
37 | + |
38 | + mir_surface_release_sync(surface); |
39 | +>>>>>>> MERGE-SOURCE |
40 | mir_connection_release(connection); |
41 | return 0; |
42 | } |
43 | |
44 | === modified file 'examples/prerendered_frames.c' |
45 | --- examples/prerendered_frames.c 2017-03-10 19:47:57 +0000 |
46 | +++ examples/prerendered_frames.c 2017-03-28 00:17:49 +0000 |
47 | @@ -234,8 +234,13 @@ |
48 | |
49 | for (i = 0u; i < num_prerendered_frames; i++) |
50 | mir_buffer_release(buffer_available[i].buffer); |
51 | +<<<<<<< TREE |
52 | mir_render_surface_release(render_surface); |
53 | mir_window_release_sync(window); |
54 | +======= |
55 | + mir_render_surface_release_sync(render_surface); |
56 | + mir_surface_release_sync(surface); |
57 | +>>>>>>> MERGE-SOURCE |
58 | mir_connection_release(connection); |
59 | return 0; |
60 | } |
61 | |
62 | === modified file 'examples/render_surface.cpp' |
63 | --- examples/render_surface.cpp 2017-03-10 19:47:57 +0000 |
64 | +++ examples/render_surface.cpp 2017-03-28 00:17:49 +0000 |
65 | @@ -23,6 +23,8 @@ |
66 | #include <signal.h> |
67 | #include <sys/signalfd.h> |
68 | #include <poll.h> |
69 | +#include <mutex> |
70 | +#include <condition_variable> |
71 | |
72 | #include "mir_toolkit/mir_client_library.h" |
73 | #include "mir_toolkit/rs/mir_render_surface.h" |
74 | @@ -207,14 +209,23 @@ |
75 | if (nformats == 0) |
76 | throw std::runtime_error("no pixel formats for buffer stream"); |
77 | printf("Software Driver selected pixel format %d\n", pixel_format); |
78 | +<<<<<<< TREE |
79 | auto buffer_stream = mir_render_surface_get_buffer_stream( |
80 | render_surface, width, height, pixel_format); |
81 | +======= |
82 | + |
83 | + auto stream = mir_render_surface_get_buffer_stream_sync( |
84 | + render_surface, |
85 | + width, height, |
86 | + pixel_format, |
87 | + mir_buffer_usage_software); |
88 | +>>>>>>> MERGE-SOURCE |
89 | |
90 | auto window = mir_create_window_sync(spec); |
91 | mir_window_spec_release(spec); |
92 | |
93 | - fill_stream_with(buffer_stream, 255, 0, 0, 128); |
94 | - mir_buffer_stream_swap_buffers_sync(buffer_stream); |
95 | + fill_stream_with(stream, 255, 0, 0, 128); |
96 | + mir_buffer_stream_swap_buffers_sync(stream); |
97 | |
98 | sigset_t halt_signals; |
99 | sigemptyset(&halt_signals); |
100 | @@ -235,13 +246,18 @@ |
101 | { |
102 | bounce_position(baseColour, dbase, 128, 255); |
103 | |
104 | - fill_stream_with(buffer_stream, baseColour, 0, 0, 128); |
105 | + fill_stream_with(stream, baseColour, 0, 0, 128); |
106 | |
107 | - mir_buffer_stream_swap_buffers_sync(buffer_stream); |
108 | + mir_buffer_stream_swap_buffers_sync(stream); |
109 | } |
110 | |
111 | +<<<<<<< TREE |
112 | mir_render_surface_release(render_surface); |
113 | mir_window_release_sync(window); |
114 | +======= |
115 | + mir_render_surface_release_sync(render_surface); |
116 | + mir_surface_release_sync(surface); |
117 | +>>>>>>> MERGE-SOURCE |
118 | close(signal_watch); |
119 | |
120 | return 0; |
121 | |
122 | === modified file 'include/client/mir_toolkit/mir_connection.h' |
123 | --- include/client/mir_toolkit/mir_connection.h 2017-03-13 08:12:52 +0000 |
124 | +++ include/client/mir_toolkit/mir_connection.h 2017-03-28 00:17:49 +0000 |
125 | @@ -63,6 +63,54 @@ |
126 | MirConnection *mir_connect_sync(char const *server, char const *app_name); |
127 | |
128 | /** |
129 | + * Request a connection to the Mir server. |
130 | + * |
131 | + * The client is responsible for handling event consumption via |
132 | + * mir_connection_dispatch(). Events will be available when the fd returned |
133 | + * by mir_connection_get_event_fd() becomes readable. |
134 | + * |
135 | + * All callbacks for this MirConnection and any objects created on it will be |
136 | + * called from the thread calling mir_connection_dispatch(). |
137 | + * |
138 | + * \param [in] server A string specifying the server to connect to. |
139 | + * Connection strings can either be path to the socket file on |
140 | + * the filesystem, or an open file descriptor fd:// |
141 | + * \param [in] app_name A name referring to the application |
142 | + * \param [in] callback Callback function to be invoked when request |
143 | + * completes. mir_connection_is_valid() will return false |
144 | + * until this callback has completed. |
145 | + * \param [in,out] context User data passed to the callback function |
146 | + * \returns The resulting MirConnection |
147 | + * \todo Currently manual dispatch interacts awkwardly with *_sync() calls; |
148 | + * Synchronous calls do *not* automatically dispatch, so unless client |
149 | + * code has a separate thread running dispatch, any *_sync() call will |
150 | + * deadlock. This restriction will be fixed in a later release. |
151 | + */ |
152 | +MirConnection* mir_connect_with_manual_dispatch(char const* server, |
153 | + char const* app_name, |
154 | + mir_connected_callback callback, |
155 | + void* context); |
156 | + |
157 | +/** |
158 | + * Synchronously connect to the Mir server. |
159 | + * |
160 | + * The client is responsible for handling event consumption via |
161 | + * mir_connection_dispatch(). Events will be available when the fd returned |
162 | + * by mir_connection_get_event_fd() becomes readable. |
163 | + * |
164 | + * All callbacks for this MirConnection and any objects created on it will be |
165 | + * called from the thread calling mir_connection_dispatch(). |
166 | + * |
167 | + * \param [in] server A string specifying the server to connect to. |
168 | + * Connection strings can either be path to the socket file on |
169 | + * the filesystem, or an open file descriptor fd:// |
170 | + * \param [in] app_name A name referring to the application |
171 | + * \returns The resulting MirConnection |
172 | + */ |
173 | +MirConnection* mir_connect_with_manual_dispatch_sync(char const* server, |
174 | + char const* app_name); |
175 | + |
176 | +/** |
177 | * Test for a valid connection |
178 | * \param [in] connection The connection |
179 | * \return True if the supplied connection is valid, or |
180 | @@ -87,6 +135,28 @@ |
181 | void mir_connection_release(MirConnection *connection); |
182 | |
183 | /** |
184 | + * \brief Get the notification fd for this connection |
185 | + * \param [in] connection The connection. This connection must have been created by |
186 | + * mir_connect_with_manual_dispatch(). |
187 | + * \return A file descriptor that supports select/poll/epoll and similar |
188 | + * APIs that becomes readable when there are events to dispatch, |
189 | + * or -1 if \ref connection was not created by |
190 | + * mir_connect_with_manual_dispatch(); |
191 | + * \note This fd is owned by the MirConnection. Do not close the fd yourself. |
192 | + * The fd remains valid until mir_connection_release() returns. |
193 | + */ |
194 | +int mir_connection_get_event_fd(MirConnection* connection); |
195 | + |
196 | +/** |
197 | + * \brief Dispatch a single pending event on the connection |
198 | + * \param [in] connection The connection. This connection must have been created by |
199 | + * mir_connect_with_manual_dispatch(). |
200 | + * \note It is an error to call this on a \ref connection not created by |
201 | + * mir_connect_with_manual_dispatch(). |
202 | + */ |
203 | +void mir_connection_dispatch(MirConnection* connection); |
204 | + |
205 | +/** |
206 | * Query platform-specific data and/or file descriptors that are required to |
207 | * initialize GL/EGL features. |
208 | * \param [in] connection The connection |
209 | |
210 | === modified file 'include/client/mir_toolkit/mir_wait.h' |
211 | --- include/client/mir_toolkit/mir_wait.h 2017-01-19 23:17:56 +0000 |
212 | +++ include/client/mir_toolkit/mir_wait.h 2017-03-28 00:17:49 +0000 |
213 | @@ -49,6 +49,7 @@ |
214 | void mir_wait_for_one(MirWaitHandle *wait_handle) |
215 | __attribute__ ((deprecated("No longer supported - use callbacks or wait for state changes"))); |
216 | |
217 | +bool mir_wait_handle_ready(MirWaitHandle* wait_handle); |
218 | |
219 | #ifdef __cplusplus |
220 | } |
221 | |
222 | === modified file 'include/client/mir_toolkit/rs/mir_render_surface.h' |
223 | --- include/client/mir_toolkit/rs/mir_render_surface.h 2017-03-14 04:41:33 +0000 |
224 | +++ include/client/mir_toolkit/rs/mir_render_surface.h 2017-03-28 00:17:49 +0000 |
225 | @@ -118,13 +118,30 @@ |
226 | /** |
227 | * Release the specified render surface |
228 | * |
229 | - * \param [in] render_surface The render surface to be released |
230 | + * \param [in] render_surface The render surface to be released |
231 | + * \param [in] callback Callback to be run when the operation completes |
232 | + * \param [in,out] ctx Context passed to callback |
233 | */ |
234 | void mir_render_surface_release( |
235 | +<<<<<<< TREE |
236 | MirRenderSurface* render_surface) |
237 | __attribute__((deprecated("This function is slated for rename due to MirRenderSurface-->MirSurface transition"))); |
238 | - |
239 | -/** |
240 | +======= |
241 | + MirRenderSurface* render_surface, |
242 | + mir_render_surface_callback callback, |
243 | + void* ctx); |
244 | + |
245 | +/** |
246 | + * Release the specified render surface and wait for the operation to complete |
247 | + * |
248 | + * \param [in] render_surface The render surface to be released |
249 | + */ |
250 | +void mir_render_surface_release_sync( |
251 | + MirRenderSurface* render_surface); |
252 | +>>>>>>> MERGE-SOURCE |
253 | + |
254 | +/** |
255 | +<<<<<<< TREE |
256 | * Obtain the buffer stream backing a given render surface. |
257 | * The MirBufferStream will contain buffers suitable for writing via the CPU. |
258 | * |
259 | @@ -143,10 +160,57 @@ |
260 | int width, int height, |
261 | MirPixelFormat format) |
262 | __attribute__((deprecated("This function is slated for rename due to MirRenderSurface-->MirSurface transition"))); |
263 | - |
264 | -/** |
265 | +======= |
266 | + * Obtain a buffer stream backing a given render surface |
267 | + * |
268 | + * \pre The MirRenderSurface does not have a backing object. |
269 | + * |
270 | + * \param [in] render_surface The render surface |
271 | + * \param [in] width Requested width |
272 | + * \param [in] height Requested height |
273 | + * \param [in] format Requested pixel format |
274 | + * \param [in] usage Requested buffer usage |
275 | + * \param [in] callback Callback to be run when operation completes |
276 | + * \param [in,out] context Context passed to callback |
277 | + */ |
278 | +void mir_render_surface_get_buffer_stream( |
279 | + MirRenderSurface* render_surface, |
280 | + int width, |
281 | + int height, |
282 | + MirPixelFormat format, |
283 | + MirBufferUsage usage, |
284 | + mir_buffer_stream_callback callback, |
285 | + void* context); |
286 | + |
287 | +/** |
288 | + * Back the render surface with a buffer stream and wait for the operation to complete. |
289 | + * |
290 | + * \pre The MirRenderSurface does not have a backing object. |
291 | + * |
292 | + * \param [in] render_surface The render surface |
293 | + * \param [in] width Requested width |
294 | + * \param [in] height Requested height |
295 | + * \param [in] format Requested pixel format |
296 | + * \param [in] usage Requested buffer usage |
297 | + * \return The new MirBufferStream backing the MirRenderSurface. |
298 | + * If a backing object for this MirRenderSurface has already been realised |
299 | + * this returns NULL, otherwise it returns a non-null MirBufferStream |
300 | + */ |
301 | +MirBufferStream* mir_render_surface_get_buffer_stream_sync( |
302 | + MirRenderSurface* render_surface, |
303 | + int width, |
304 | + int height, |
305 | + MirPixelFormat format, |
306 | + MirBufferUsage usage); |
307 | +>>>>>>> MERGE-SOURCE |
308 | + |
309 | +/** |
310 | +<<<<<<< TREE |
311 | * Obtain the presentation chain backing a given render surface. |
312 | * The MirPresentationChain is created in mir_present_mode_fifo submission mode. |
313 | +======= |
314 | + * Obtain a presentation chain backing a given render surface |
315 | +>>>>>>> MERGE-SOURCE |
316 | * |
317 | * \return The chain contained in the given render surface |
318 | * or 'nullptr' if it, or |
319 | |
320 | === added file 'include/common/mir/dispatch/threaded_dispatcher.h.moved' |
321 | --- include/common/mir/dispatch/threaded_dispatcher.h.moved 1970-01-01 00:00:00 +0000 |
322 | +++ include/common/mir/dispatch/threaded_dispatcher.h.moved 2017-03-28 00:17:49 +0000 |
323 | @@ -0,0 +1,75 @@ |
324 | +/* |
325 | + * Copyright © 2015 Canonical Ltd. |
326 | + * |
327 | + * This program is free software: you can redistribute it and/or modify it |
328 | + * under the terms of the GNU Lesser General Public License version 3, |
329 | + * as published by the Free Software Foundation. |
330 | + * |
331 | + * This program is distributed in the hope that it will be useful, |
332 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
333 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
334 | + * GNU Lesser General Public License for more details. |
335 | + * |
336 | + * You should have received a copy of the GNU Lesser General Public License |
337 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
338 | + * |
339 | + * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com> |
340 | + */ |
341 | + |
342 | +#ifndef MIR_DISPATCH_SIMPLE_DISPATCH_THREAD_H_ |
343 | +#define MIR_DISPATCH_SIMPLE_DISPATCH_THREAD_H_ |
344 | + |
345 | +#include <string> |
346 | +#include <memory> |
347 | +#include <thread> |
348 | +#include <vector> |
349 | +#include <mutex> |
350 | +#include <condition_variable> |
351 | + |
352 | +#include "mir/dispatch/multiplexing_dispatchable.h" |
353 | +#include "mir/fd.h" |
354 | + |
355 | +namespace mir |
356 | +{ |
357 | +namespace dispatch |
358 | +{ |
359 | +class Dispatchable; |
360 | + |
361 | +class ThreadedDispatcher |
362 | +{ |
363 | +public: |
364 | + ThreadedDispatcher(std::string const& name, std::shared_ptr<Dispatchable> const& dispatchee); |
365 | + ThreadedDispatcher(std::string const& name, |
366 | + std::shared_ptr<Dispatchable> const& dispatchee, |
367 | + std::function<void()> const& exception_handler); |
368 | + ~ThreadedDispatcher() noexcept; |
369 | + |
370 | + void add_thread(); |
371 | + void remove_thread(); |
372 | + |
373 | +private: |
374 | + class ThreadShutdownRequestHandler; |
375 | + friend class ThreadShutdownRequestHandler; |
376 | + |
377 | + std::string const name_base; |
378 | + |
379 | + std::shared_ptr<ThreadShutdownRequestHandler> thread_exiter; |
380 | + std::shared_ptr<MultiplexingDispatchable> dispatcher; |
381 | + |
382 | + std::mutex thread_pool_mutex; |
383 | + std::vector<std::thread> threadpool; |
384 | + |
385 | + std::function<void()> const exception_handler; |
386 | + |
387 | + static void dispatch_loop(std::string const& name, |
388 | + std::shared_ptr<ThreadShutdownRequestHandler> thread_register, |
389 | + std::shared_ptr<Dispatchable> dispatcher, |
390 | + std::function<void()> const& exception_handler); |
391 | + |
392 | +}; |
393 | + |
394 | +} |
395 | +} |
396 | + |
397 | + |
398 | +#endif // MIR_DISPATCH_SIMPLE_DISPATCH_THREAD_H_ |
399 | |
400 | === renamed file 'tests/include/mir/test/fd_utils.h' => 'include/test/mir/test/fd_utils.h' |
401 | === modified file 'include/test/mir/test/validity_matchers.h' |
402 | --- include/test/mir/test/validity_matchers.h 2017-01-18 02:29:37 +0000 |
403 | +++ include/test/mir/test/validity_matchers.h 2017-03-28 00:17:49 +0000 |
404 | @@ -23,6 +23,8 @@ |
405 | |
406 | #include "mir_toolkit/mir_client_library.h" |
407 | |
408 | +class MirRenderSurface; |
409 | + |
410 | using ::testing::MakePolymorphicMatcher; |
411 | using ::testing::MatchResultListener; |
412 | using ::testing::NotNull; |
413 | @@ -54,6 +56,12 @@ |
414 | template<> |
415 | bool IsValidMatcher::MatchAndExplain(MirWindow* surface, MatchResultListener* listener) const; |
416 | |
417 | +template<> |
418 | +bool IsValidMatcher::MatchAndExplain(MirBufferStream* stream, MatchResultListener* listener) const; |
419 | + |
420 | +template<> |
421 | +bool IsValidMatcher::MatchAndExplain(MirRenderSurface* stream, MatchResultListener* listener) const; |
422 | + |
423 | // To construct a polymorphic matcher, pass an instance of the class |
424 | // to MakePolymorphicMatcher(). Note the return type. |
425 | inline PolymorphicMatcher<IsValidMatcher> IsValid() |
426 | |
427 | === modified file 'playground/egldiamond_render_surface.c' |
428 | --- playground/egldiamond_render_surface.c 2017-03-14 04:41:33 +0000 |
429 | +++ playground/egldiamond_render_surface.c 2017-03-28 00:17:49 +0000 |
430 | @@ -322,8 +322,13 @@ |
431 | future_driver_eglTerminate(egldisplay); |
432 | else |
433 | eglTerminate(egldisplay); |
434 | +<<<<<<< TREE |
435 | mir_render_surface_release(render_surface); |
436 | mir_window_release_sync(window); |
437 | +======= |
438 | + mir_render_surface_release_sync(render_surface); |
439 | + mir_surface_release_sync(surface); |
440 | +>>>>>>> MERGE-SOURCE |
441 | mir_connection_release(connection); |
442 | return 0; |
443 | } |
444 | |
445 | === modified file 'playground/mir_egl_platform_shim.c' |
446 | --- playground/mir_egl_platform_shim.c 2017-03-10 19:47:57 +0000 |
447 | +++ playground/mir_egl_platform_shim.c 2017-03-28 00:17:49 +0000 |
448 | @@ -72,10 +72,19 @@ |
449 | MirPixelFormat pixel_format = mir_connection_get_egl_pixel_format(info->connection, display, config); |
450 | //this particular [silly] driver has chosen the buffer stream as the way it wants to post |
451 | //its hardware content. I'd think most drivers would want MirPresentationChain for flexibility |
452 | +<<<<<<< TREE |
453 | info->stream = ext->get_hardware_buffer_stream(surface, |
454 | info->current_physical_width, |
455 | info->current_physical_height, |
456 | pixel_format); |
457 | +======= |
458 | + |
459 | + info->stream = mir_render_surface_get_buffer_stream_sync( |
460 | + surface, |
461 | + info->current_physical_width, info->current_physical_height, |
462 | + pixel_format, |
463 | + mir_buffer_usage_hardware); |
464 | +>>>>>>> MERGE-SOURCE |
465 | |
466 | printf("The driver chose pixel format %d.\n", pixel_format); |
467 | return eglCreateWindowSurface(display, config, (EGLNativeWindowType) surface, attr); |
468 | |
469 | === modified file 'src/client/CMakeLists.txt' |
470 | --- src/client/CMakeLists.txt 2017-03-21 05:51:47 +0000 |
471 | +++ src/client/CMakeLists.txt 2017-03-28 00:17:49 +0000 |
472 | @@ -81,12 +81,15 @@ |
473 | screencast_stream.cpp |
474 | buffer_vault.cpp |
475 | mir_buffer_stream_api.cpp |
476 | + synchronous_helper.cpp |
477 | error_stream.cpp |
478 | error_render_surface.cpp |
479 | buffer.cpp |
480 | error_buffer.cpp |
481 | mir_render_surface_api.cpp |
482 | render_surface.cpp |
483 | + mir_render_surface.h |
484 | + ${CMAKE_SOURCE_DIR}/src/include/client/mir_toolkit/mir_render_surface.h |
485 | presentation_chain.cpp |
486 | mir_presentation_chain_api.cpp |
487 | mir_buffer_api.cpp |
488 | @@ -104,7 +107,11 @@ |
489 | ${CMAKE_SOURCE_DIR}/include/client/mir_toolkit/mir_error.h |
490 | mir_extension_core.cpp |
491 | ${CMAKE_SOURCE_DIR}/include/client/mir_toolkit/mir_extension_core.h |
492 | +<<<<<<< TREE |
493 | ${CMAKE_SOURCE_DIR}/include/client/mir_toolkit/extensions/drag_and_drop.h |
494 | +======= |
495 | + no_tls_future-inl.h |
496 | +>>>>>>> MERGE-SOURCE |
497 | ) |
498 | |
499 | # Ensure protobuf C++ headers have been produced before |
500 | @@ -160,6 +167,8 @@ |
501 | |
502 | add_library(mirclient-debug-extension SHARED |
503 | mir_debug_api.cpp |
504 | + $<TARGET_OBJECTS:mirclientobjects> |
505 | + $<TARGET_OBJECTS:mirsharedinput> |
506 | ) |
507 | |
508 | target_link_libraries(mirclient-debug-extension |
509 | |
510 | === modified file 'src/client/buffer_factory.cpp' |
511 | --- src/client/buffer_factory.cpp 2017-03-10 19:47:57 +0000 |
512 | +++ src/client/buffer_factory.cpp 2017-03-28 00:17:49 +0000 |
513 | @@ -22,6 +22,7 @@ |
514 | #include <algorithm> |
515 | #include <boost/throw_exception.hpp> |
516 | #include "protobuf_to_native_buffer.h" |
517 | +#include <sstream> |
518 | |
519 | namespace mcl = mir::client; |
520 | namespace geom = mir::geometry; |
521 | @@ -92,7 +93,16 @@ |
522 | }); |
523 | |
524 | if (request_it == allocation_requests.end()) |
525 | - BOOST_THROW_EXCEPTION(std::logic_error("unrequested buffer received")); |
526 | + { |
527 | + std::stringstream message; |
528 | + message << "Unrequested buffer received. Expected a buffer with one of the following sizes:" << std::endl; |
529 | + for (auto const& request : allocation_requests) |
530 | + { |
531 | + message << "\t(" << request->size.width << "×" << request->size.height << ")" << std::endl; |
532 | + } |
533 | + message << "Received buffer has size: (" << buffer.width() << "×" << buffer.height() << ")" << std::endl; |
534 | + BOOST_THROW_EXCEPTION(std::logic_error{message.str()}); |
535 | + } |
536 | |
537 | std::unique_ptr<mcl::MirBuffer> b; |
538 | if (buffer.has_error()) |
539 | |
540 | === modified file 'src/client/buffer_stream.cpp' |
541 | --- src/client/buffer_stream.cpp 2017-03-20 11:24:19 +0000 |
542 | +++ src/client/buffer_stream.cpp 2017-03-28 00:17:49 +0000 |
543 | @@ -142,37 +142,52 @@ |
544 | //Should be merged with mcl::BufferVault |
545 | struct BufferDepository |
546 | { |
547 | - BufferDepository( |
548 | + static NoTLSFuture<std::unique_ptr<BufferDepository>> create( |
549 | std::shared_ptr<mcl::ClientBufferFactory> const& factory, |
550 | std::shared_ptr<mcl::AsyncBufferFactory> const& mirbuffer_factory, |
551 | std::shared_ptr<mcl::ServerBufferRequests> const& requests, |
552 | std::weak_ptr<mcl::SurfaceMap> const& surface_map, |
553 | geom::Size size, MirPixelFormat format, int usage, |
554 | - unsigned int initial_nbuffers) : |
555 | - vault(factory, mirbuffer_factory, requests, surface_map, size, format, usage, initial_nbuffers), |
556 | - current(nullptr), |
557 | - size_(size) |
558 | + unsigned int initial_nbuffers) |
559 | { |
560 | - future = vault.withdraw(); |
561 | + auto vault = std::make_unique<mcl::BufferVault>( |
562 | + factory, |
563 | + mirbuffer_factory, |
564 | + requests, |
565 | + surface_map, |
566 | + size, |
567 | + format, |
568 | + usage, |
569 | + initial_nbuffers); |
570 | + |
571 | + auto future_buffer = vault->withdraw(); |
572 | + |
573 | + // Because NoTLSFuture<>.then() internally uses a std::function<void()> for the |
574 | + // continuation the lambda passed in has to be CopyConstructible, which means we can't |
575 | + // move-capture a std::unique_ptr<>. Dance around it with release(). |
576 | + return future_buffer.then( |
577 | + [raw_vault = vault.release(), size](auto&& resolved_buffer) |
578 | + { |
579 | + std::unique_ptr<mcl::BufferVault> vault{raw_vault}; |
580 | + return std::unique_ptr<BufferDepository>( |
581 | + new BufferDepository{ |
582 | + resolved_buffer.get(), |
583 | + std::move(vault), |
584 | + size}); |
585 | + }); |
586 | } |
587 | |
588 | void deposit(mp::Buffer const&, mir::optional_value<geom::Size>, MirPixelFormat) |
589 | { |
590 | } |
591 | |
592 | - void advance_current_buffer(std::unique_lock<std::mutex>& lk) |
593 | - { |
594 | - lk.unlock(); |
595 | - auto c = future.get(); |
596 | - lk.lock(); |
597 | - current = c; |
598 | - } |
599 | - |
600 | std::shared_ptr<mir::client::ClientBuffer> current_buffer() |
601 | { |
602 | std::unique_lock<std::mutex> lk(mutex); |
603 | if (!current) |
604 | - advance_current_buffer(lk); |
605 | + BOOST_THROW_EXCEPTION( |
606 | + std::logic_error{ |
607 | + "Current buffer requested before waiting for buffer to arrive"}); |
608 | return current->client_buffer(); |
609 | } |
610 | |
611 | @@ -180,7 +195,9 @@ |
612 | { |
613 | std::unique_lock<std::mutex> lk(mutex); |
614 | if (!current) |
615 | - advance_current_buffer(lk); |
616 | + BOOST_THROW_EXCEPTION( |
617 | + std::logic_error{ |
618 | + "Current buffer requested before waiting for buffer to arrive"}); |
619 | return current->rpc_id(); |
620 | } |
621 | |
622 | @@ -188,16 +205,23 @@ |
623 | { |
624 | std::unique_lock<std::mutex> lk(mutex); |
625 | if (!current) |
626 | - advance_current_buffer(lk); |
627 | + BOOST_THROW_EXCEPTION( |
628 | + std::logic_error{ |
629 | + "Attempted to submit current buffer without waiting for a buffer to become current"}); |
630 | auto c = current; |
631 | current = nullptr; |
632 | lk.unlock(); |
633 | |
634 | - vault.deposit(c); |
635 | - auto wh = vault.wire_transfer_outbound(c, done); |
636 | - auto f = vault.withdraw(); |
637 | - lk.lock(); |
638 | - future = std::move(f); |
639 | + vault->deposit(c); |
640 | + auto wh = vault->wire_transfer_outbound(c, done); |
641 | + |
642 | + vault->withdraw().then( |
643 | + [this](auto&& new_buffer) |
644 | + { |
645 | + std::lock_guard<std::mutex> lk{mutex}; |
646 | + |
647 | + current = new_buffer.get(); |
648 | + }).detach(); |
649 | return wh; |
650 | } |
651 | |
652 | @@ -207,7 +231,7 @@ |
653 | std::unique_lock<std::mutex> lk(mutex); |
654 | size_ = size; |
655 | } |
656 | - vault.set_size(size); |
657 | + vault->set_size(size); |
658 | } |
659 | |
660 | geom::Size size() const |
661 | @@ -218,14 +242,14 @@ |
662 | |
663 | void lost_connection() |
664 | { |
665 | - vault.disconnected(); |
666 | + vault->disconnected(); |
667 | } |
668 | |
669 | MirWaitHandle* set_scale(float scale, mf::BufferStreamId) |
670 | { |
671 | scale_wait_handle.expect_result(); |
672 | scale_wait_handle.result_received(); |
673 | - vault.set_scale(scale); |
674 | + vault->set_scale(scale); |
675 | return &scale_wait_handle; |
676 | } |
677 | |
678 | @@ -233,15 +257,24 @@ |
679 | { |
680 | std::unique_lock<decltype(mutex)> lk(mutex); |
681 | interval = std::max(0, std::min(1, interval)); |
682 | - vault.set_interval(interval); |
683 | - } |
684 | - |
685 | - // Future must be before vault, to ensure vault's destruction marks future |
686 | - // as ready. |
687 | - mir::client::NoTLSFuture<std::shared_ptr<mcl::MirBuffer>> future; |
688 | - |
689 | - mcl::BufferVault vault; |
690 | + vault->set_interval(interval); |
691 | + } |
692 | + |
693 | + |
694 | +private: |
695 | + BufferDepository( |
696 | + std::shared_ptr<mcl::MirBuffer> initial_buffer, |
697 | + std::unique_ptr<mcl::BufferVault>&& vault, |
698 | + geom::Size size) : |
699 | + vault{std::move(vault)}, |
700 | + current{initial_buffer}, |
701 | + size_{size} |
702 | + { |
703 | + } |
704 | + |
705 | + std::unique_ptr<mcl::BufferVault> vault; |
706 | std::mutex mutable mutex; |
707 | + std::mutex current_buffer_mutex; |
708 | std::shared_ptr<mcl::MirBuffer> current{nullptr}; |
709 | MirWaitHandle scale_wait_handle; |
710 | geom::Size size_; |
711 | @@ -249,12 +282,17 @@ |
712 | } |
713 | } |
714 | |
715 | +<<<<<<< TREE |
716 | #pragma GCC diagnostic push |
717 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" |
718 | mcl::BufferStream::BufferStream( |
719 | +======= |
720 | +mcl::NoTLSFuture<std::unique_ptr<mcl::BufferStream>> |
721 | +mcl::BufferStream::create( |
722 | +>>>>>>> MERGE-SOURCE |
723 | MirConnection* connection, |
724 | MirRenderSurface* render_surface, |
725 | - std::shared_ptr<MirWaitHandle> creation_wait_handle, |
726 | + std::shared_ptr<MirWaitHandle> const& creation_wait_handle, |
727 | mclr::DisplayServer& server, |
728 | std::shared_ptr<mcl::ClientPlatform> const& client_platform, |
729 | std::weak_ptr<mcl::SurfaceMap> const& map, |
730 | @@ -264,22 +302,87 @@ |
731 | std::string const& surface_name, |
732 | geom::Size ideal_size, |
733 | size_t nbuffers) |
734 | +{ |
735 | + auto protobuf_bs = mcl::make_protobuf_object(a_protobuf_bs); |
736 | + |
737 | + if (!protobuf_bs->has_id()) |
738 | + { |
739 | + if (!protobuf_bs->has_error()) |
740 | + protobuf_bs->set_error("Error processing buffer stream create response, no ID (disconnected?)"); |
741 | + } |
742 | + |
743 | + if (protobuf_bs->has_error()) |
744 | + { |
745 | + if (protobuf_bs->has_buffer()) |
746 | + { |
747 | + for (int i = 0; i < protobuf_bs->buffer().fd_size(); i++) |
748 | + ::close(protobuf_bs->buffer().fd(i)); |
749 | + } |
750 | + |
751 | + BOOST_THROW_EXCEPTION(std::runtime_error("Can not create buffer stream: " + std::string(protobuf_bs->error()))); |
752 | + } |
753 | + |
754 | + |
755 | + auto future_depository = BufferDepository::create( |
756 | + client_platform->create_buffer_factory(), factory, |
757 | + std::make_shared<Requests>(server, protobuf_bs->id().value()), map, |
758 | + ideal_size, static_cast<MirPixelFormat>(protobuf_bs->pixel_format()), |
759 | + protobuf_bs->buffer_usage(), nbuffers); |
760 | + |
761 | + return future_depository.then( |
762 | + [=, raw_protobuf_bs = protobuf_bs.release(), raw_server = &server](auto&& depository) |
763 | + { |
764 | + std::unique_ptr<mp::BufferStream> protobuf_bs{raw_protobuf_bs}; |
765 | + // Can't use make_unique because the constructor is private to it. |
766 | + return std::unique_ptr<BufferStream>{ |
767 | + new BufferStream{ |
768 | + *raw_server, |
769 | + connection, |
770 | + render_surface, |
771 | + creation_wait_handle, |
772 | + depository.get(), |
773 | + client_platform, |
774 | + map, |
775 | + std::move(protobuf_bs), |
776 | + perf_report, |
777 | + surface_name, |
778 | + ideal_size}}; |
779 | + } |
780 | + ); |
781 | +} |
782 | + |
783 | +mcl::BufferStream::BufferStream( |
784 | + rpc::DisplayServer& server, |
785 | + MirConnection* connection, |
786 | + MirRenderSurface* render_surface, |
787 | + std::shared_ptr<MirWaitHandle> const& creation_wait_handle, |
788 | + std::unique_ptr<BufferDepository>&& depository, |
789 | + std::shared_ptr<mcl::ClientPlatform> const& client_platform, |
790 | + std::weak_ptr<mcl::SurfaceMap> const& map, |
791 | + std::unique_ptr<mp::BufferStream>&& incoming_protobuf_bs, |
792 | + std::shared_ptr<mcl::PerfReport> const& perf_report, |
793 | + std::string const& surface_name, |
794 | + geom::Size ideal_size) |
795 | : connection_(connection), |
796 | client_platform(client_platform), |
797 | - protobuf_bs{mcl::make_protobuf_object<mir::protobuf::BufferStream>(a_protobuf_bs)}, |
798 | + protobuf_bs{std::move(incoming_protobuf_bs)}, |
799 | user_swap_interval(parse_env_for_swap_interval()), |
800 | +<<<<<<< TREE |
801 | using_client_side_vsync(false), |
802 | interval_config{server, frontend::BufferStreamId{a_protobuf_bs.id().value()}}, |
803 | +======= |
804 | + interval_config{server, frontend::BufferStreamId{this->protobuf_bs->id().value()}}, |
805 | +>>>>>>> MERGE-SOURCE |
806 | scale_(1.0f), |
807 | perf_report(perf_report), |
808 | protobuf_void{mcl::make_protobuf_object<mir::protobuf::Void>()}, |
809 | + buffer_depository{std::move(depository)}, |
810 | ideal_buffer_size(ideal_size), |
811 | - nbuffers(nbuffers), |
812 | - creation_wait_handle(creation_wait_handle), |
813 | + creation_wait_handle{creation_wait_handle}, |
814 | map(map), |
815 | - factory(factory), |
816 | render_surface_(render_surface) |
817 | { |
818 | +<<<<<<< TREE |
819 | /* |
820 | * Since we try to use client-side vsync where possible, a separate |
821 | * copy of the current swap interval is required to represent that |
822 | @@ -306,9 +409,12 @@ |
823 | |
824 | BOOST_THROW_EXCEPTION(std::runtime_error("Can not create buffer stream: " + std::string(protobuf_bs->error()))); |
825 | } |
826 | +======= |
827 | +>>>>>>> MERGE-SOURCE |
828 | |
829 | try |
830 | { |
831 | +<<<<<<< TREE |
832 | buffer_depository = std::make_unique<BufferDepository>( |
833 | client_platform->create_buffer_factory(), factory, |
834 | std::make_shared<Requests>(server, protobuf_bs->id().value(), client_platform), |
835 | @@ -316,6 +422,8 @@ |
836 | ideal_buffer_size, static_cast<MirPixelFormat>(protobuf_bs->pixel_format()), |
837 | protobuf_bs->buffer_usage(), nbuffers); |
838 | |
839 | +======= |
840 | +>>>>>>> MERGE-SOURCE |
841 | egl_native_window_ = client_platform->create_egl_native_window(this); |
842 | |
843 | // This might seem like something to provide during creation but |
844 | |
845 | === modified file 'src/client/buffer_stream.h' |
846 | --- src/client/buffer_stream.h 2017-03-20 11:24:19 +0000 |
847 | +++ src/client/buffer_stream.h 2017-03-28 00:17:49 +0000 |
848 | @@ -26,10 +26,15 @@ |
849 | #include "mir/geometry/size.h" |
850 | #include "mir/optional_value.h" |
851 | #include "buffer_stream_configuration.h" |
852 | +<<<<<<< TREE |
853 | #include "frame_clock.h" |
854 | +======= |
855 | +#include "no_tls_future-inl.h" |
856 | +>>>>>>> MERGE-SOURCE |
857 | |
858 | #include "mir_toolkit/client_types.h" |
859 | |
860 | + |
861 | #include <EGL/eglplatform.h> |
862 | |
863 | #include <unordered_set> |
864 | @@ -74,15 +79,19 @@ |
865 | class BufferStream : public EGLNativeSurface, public MirBufferStream |
866 | { |
867 | public: |
868 | +<<<<<<< TREE |
869 | BufferStream( |
870 | mir::client::rpc::DisplayServer& server, |
871 | std::weak_ptr<SurfaceMap> const& map); |
872 | #pragma GCC diagnostic push |
873 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" |
874 | BufferStream( |
875 | +======= |
876 | + static NoTLSFuture<std::unique_ptr<BufferStream>> create( |
877 | +>>>>>>> MERGE-SOURCE |
878 | MirConnection* connection, |
879 | MirRenderSurface* render_surface, |
880 | - std::shared_ptr<MirWaitHandle> creation_wait_handle, |
881 | + std::shared_ptr<MirWaitHandle> const& creation_wait_handle, |
882 | mir::client::rpc::DisplayServer& server, |
883 | std::shared_ptr<ClientPlatform> const& native_window_factory, |
884 | std::weak_ptr<SurfaceMap> const& map, |
885 | @@ -139,6 +148,19 @@ |
886 | BufferStream& operator=(BufferStream const&) = delete; |
887 | |
888 | private: |
889 | + BufferStream( |
890 | + rpc::DisplayServer& server, |
891 | + MirConnection* connection, |
892 | + MirRenderSurface* render_surface, |
893 | + std::shared_ptr<MirWaitHandle> const& creation_wait_handle, |
894 | + std::unique_ptr<BufferDepository>&& depository, |
895 | + std::shared_ptr<ClientPlatform> const& native_window_factory, |
896 | + std::weak_ptr<SurfaceMap> const& map, |
897 | + std::unique_ptr<mir::protobuf::BufferStream>&& protobuf_bs, |
898 | + std::shared_ptr<PerfReport> const& perf_report, |
899 | + std::string const& surface_name, |
900 | + geometry::Size ideal_size); |
901 | + |
902 | void process_buffer(protobuf::Buffer const& buffer); |
903 | void process_buffer(protobuf::Buffer const& buffer, std::unique_lock<std::mutex>&); |
904 | MirWaitHandle* set_server_swap_interval(int i); |
905 | @@ -165,13 +187,15 @@ |
906 | |
907 | std::unique_ptr<BufferDepository> buffer_depository; |
908 | geometry::Size ideal_buffer_size; |
909 | - size_t const nbuffers; |
910 | std::string error_message; |
911 | - std::shared_ptr<MirWaitHandle> creation_wait_handle; |
912 | + std::shared_ptr<MirWaitHandle> const creation_wait_handle; |
913 | std::weak_ptr<SurfaceMap> const map; |
914 | +<<<<<<< TREE |
915 | std::shared_ptr<AsyncBufferFactory> const factory; |
916 | #pragma GCC diagnostic push |
917 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" |
918 | +======= |
919 | +>>>>>>> MERGE-SOURCE |
920 | MirRenderSurface* render_surface_; |
921 | #pragma GCC diagnostic pop |
922 | |
923 | |
924 | === modified file 'src/client/buffer_stream_configuration.cpp' |
925 | --- src/client/buffer_stream_configuration.cpp 2017-01-18 02:29:37 +0000 |
926 | +++ src/client/buffer_stream_configuration.cpp 2017-03-28 00:17:49 +0000 |
927 | @@ -29,6 +29,14 @@ |
928 | { |
929 | } |
930 | |
931 | +mcl::BufferStreamConfiguration::BufferStreamConfiguration( |
932 | + BufferStreamConfiguration&& from) |
933 | + : server{from.server}, |
934 | + id{from.id}, |
935 | + protobuf_void{std::move(from.protobuf_void)} |
936 | +{ |
937 | +} |
938 | + |
939 | void mcl::BufferStreamConfiguration::on_swap_interval_set(int interval) |
940 | { |
941 | std::unique_lock<decltype(mutex)> lock(mutex); |
942 | |
943 | === modified file 'src/client/buffer_stream_configuration.h' |
944 | --- src/client/buffer_stream_configuration.h 2017-01-18 02:29:37 +0000 |
945 | +++ src/client/buffer_stream_configuration.h 2017-03-28 00:17:49 +0000 |
946 | @@ -33,6 +33,7 @@ |
947 | { |
948 | public: |
949 | BufferStreamConfiguration(rpc::DisplayServer& server, frontend::BufferStreamId id); |
950 | + BufferStreamConfiguration(BufferStreamConfiguration&& from); |
951 | |
952 | void on_swap_interval_set(int interval); |
953 | int swap_interval() const; |
954 | |
955 | === modified file 'src/client/buffer_vault.cpp' |
956 | --- src/client/buffer_vault.cpp 2017-01-30 08:13:20 +0000 |
957 | +++ src/client/buffer_vault.cpp 2017-03-28 00:17:49 +0000 |
958 | @@ -28,6 +28,7 @@ |
959 | #include "buffer_factory.h" |
960 | #include "buffer.h" |
961 | #include <algorithm> |
962 | +#include <experimental/optional> |
963 | #include <boost/throw_exception.hpp> |
964 | |
965 | namespace mcl = mir::client; |
966 | @@ -271,14 +272,30 @@ |
967 | } |
968 | } |
969 | |
970 | + auto cb = deferred_cb; |
971 | + deferred_cb = {}; |
972 | + std::experimental::optional<decltype(promises)::value_type> buffer_promise; |
973 | + |
974 | if (!promises.empty()) |
975 | { |
976 | buffers[buffer_id] = Owner::ContentProducer; |
977 | - promises.front().set_value(buffer); |
978 | - promises.pop_front(); |
979 | - } |
980 | - |
981 | - trigger_callback(std::move(lk)); |
982 | + // Satisfying a promise might call continuation code on this stack. |
983 | + // We need to |
984 | + buffer_promise = std::move(promises.front()); |
985 | + promises.pop_front();; |
986 | + } |
987 | + |
988 | + lk.unlock(); |
989 | + |
990 | + if (buffer_promise) |
991 | + { |
992 | + buffer_promise->set_value(buffer); |
993 | + } |
994 | + if (cb) |
995 | + { |
996 | + cb(); |
997 | + swap_buffers_wait_handle.result_received(); |
998 | + } |
999 | } |
1000 | |
1001 | void mcl::BufferVault::disconnected() |
1002 | |
1003 | === added file 'src/client/client_buffer_stream_factory.h.THIS' |
1004 | --- src/client/client_buffer_stream_factory.h.THIS 1970-01-01 00:00:00 +0000 |
1005 | +++ src/client/client_buffer_stream_factory.h.THIS 2017-03-28 00:17:49 +0000 |
1006 | @@ -0,0 +1,66 @@ |
1007 | +/* |
1008 | + * Copyright © 2015 Canonical Ltd. |
1009 | + * |
1010 | + * This program is free software: you can redistribute it and/or modify it |
1011 | + * under the terms of the GNU Lesser General Public License version 3, |
1012 | + * as published by the Free Software Foundation. |
1013 | + * |
1014 | + * This program is distributed in the hope that it will be useful, |
1015 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1016 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1017 | + * GNU Lesser General Public License for more details. |
1018 | + * |
1019 | + * You should have received a copy of the GNU Lesser General Public License |
1020 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1021 | + * |
1022 | + * Authored by: Robert Carr <robert.carr@canonical.com> |
1023 | + */ |
1024 | + |
1025 | +#ifndef MIR_CLIENT_CLIENT_BUFFER_STREAM_FACTORY_H_ |
1026 | +#define MIR_CLIENT_CLIENT_BUFFER_STREAM_FACTORY_H_ |
1027 | + |
1028 | +#include "mir_protobuf.pb.h" |
1029 | + |
1030 | +#include "mir_toolkit/client_types.h" |
1031 | + |
1032 | +#include <memory> |
1033 | + |
1034 | +class MirConnection; |
1035 | + |
1036 | +namespace mir |
1037 | +{ |
1038 | +namespace client |
1039 | +{ |
1040 | +class ClientBufferStream; |
1041 | +class BufferStream; |
1042 | +class ClientBufferStreamFactory |
1043 | +{ |
1044 | +public: |
1045 | + virtual std::shared_ptr<ClientBufferStream> make_consumer_stream( |
1046 | + MirConnection* allocating_connection, |
1047 | + protobuf::DisplayServer& server, |
1048 | + protobuf::BufferStream const& protobuf_bs, |
1049 | + std::string const& surface_name) = 0; |
1050 | + virtual std::shared_ptr<ClientBufferStream> make_producer_stream( |
1051 | + MirConnection* allocating_connection, |
1052 | + protobuf::DisplayServer& server, |
1053 | + protobuf::BufferStream const& protobuf_bs, |
1054 | + std::string const& surface_name) = 0; |
1055 | + |
1056 | + // For creating buffer stream owned by client. |
1057 | + virtual ClientBufferStream* make_producer_stream( |
1058 | + MirConnection* allocating_connection, |
1059 | + protobuf::DisplayServer& server, |
1060 | + protobuf::BufferStreamParameters const& params, |
1061 | + mir_buffer_stream_callback callback, void* context) = 0; |
1062 | + |
1063 | +protected: |
1064 | + ClientBufferStreamFactory() = default; |
1065 | + virtual ~ClientBufferStreamFactory() = default; |
1066 | + ClientBufferStreamFactory(const ClientBufferStreamFactory&) = delete; |
1067 | + ClientBufferStreamFactory& operator=(const ClientBufferStreamFactory&) = delete; |
1068 | +}; |
1069 | +} |
1070 | +} |
1071 | + |
1072 | +#endif // MIR_CLIENT_CLIENT_BUFFER_STREAM_FACTORY_H_ |
1073 | |
1074 | === modified file 'src/client/connection_configuration.h' |
1075 | --- src/client/connection_configuration.h 2017-02-15 14:45:41 +0000 |
1076 | +++ src/client/connection_configuration.h 2017-03-28 00:17:49 +0000 |
1077 | @@ -37,6 +37,11 @@ |
1078 | class Logger; |
1079 | } |
1080 | |
1081 | +namespace dispatch |
1082 | +{ |
1083 | +class ActionQueue; |
1084 | +} |
1085 | + |
1086 | namespace client |
1087 | { |
1088 | namespace rpc |
1089 | @@ -51,11 +56,17 @@ |
1090 | class EventHandlerRegister; |
1091 | class AsyncBufferFactory; |
1092 | |
1093 | +namespace rpc |
1094 | +{ |
1095 | +class MirBasicRpcChannel; |
1096 | +} |
1097 | + |
1098 | class ConnectionConfiguration |
1099 | { |
1100 | public: |
1101 | virtual ~ConnectionConfiguration() = default; |
1102 | |
1103 | + virtual std::shared_ptr<dispatch::ActionQueue> the_delayed_queue() = 0; |
1104 | virtual std::shared_ptr<ConnectionSurfaceMap> the_surface_map() = 0; |
1105 | virtual std::shared_ptr<mir::client::rpc::MirBasicRpcChannel> the_rpc_channel() = 0; |
1106 | virtual std::shared_ptr<mir::logging::Logger> the_logger() = 0; |
1107 | |
1108 | === modified file 'src/client/connection_surface_map.cpp' |
1109 | --- src/client/connection_surface_map.cpp 2017-03-14 04:41:33 +0000 |
1110 | +++ src/client/connection_surface_map.cpp 2017-03-28 00:17:49 +0000 |
1111 | @@ -20,26 +20,78 @@ |
1112 | #include "mir_surface.h" |
1113 | #include "presentation_chain.h" |
1114 | |
1115 | +#include "mir/dispatch/action_queue.h" |
1116 | + |
1117 | #include <boost/throw_exception.hpp> |
1118 | #include <sstream> |
1119 | |
1120 | namespace mcl=mir::client; |
1121 | namespace mf=mir::frontend; |
1122 | |
1123 | +<<<<<<< TREE |
1124 | using mir::client::ConnectionSurfaceMap; |
1125 | using mir::frontend::SurfaceId; |
1126 | using mir::frontend::BufferStreamId; |
1127 | |
1128 | std::shared_ptr<MirWindow> ConnectionSurfaceMap::surface(SurfaceId id) const |
1129 | -{ |
1130 | +======= |
1131 | +mcl::ConnectionSurfaceMap::ConnectionSurfaceMap( |
1132 | + std::shared_ptr<dispatch::ActionQueue> delayed_queue) |
1133 | + : delayed_queue{delayed_queue} |
1134 | +{ |
1135 | +} |
1136 | + |
1137 | +void mcl::ConnectionSurfaceMap::with_surface_do( |
1138 | + mf::SurfaceId surface_id, std::function<void(MirSurface*)> const& exec) const |
1139 | +>>>>>>> MERGE-SOURCE |
1140 | +{ |
1141 | + { |
1142 | + std::lock_guard<decltype(reserved_guard)> lock{reserved_guard}; |
1143 | + auto const it = surface_reservations.find(surface_id); |
1144 | + if (it != surface_reservations.end()) |
1145 | + { |
1146 | + it->second.push_back(exec); |
1147 | + return; |
1148 | + } |
1149 | + } |
1150 | + |
1151 | std::shared_lock<decltype(guard)> lk(guard); |
1152 | auto const found = surfaces.find(id); |
1153 | return found != surfaces.end() ? found->second : nullptr; |
1154 | } |
1155 | |
1156 | +<<<<<<< TREE |
1157 | void mcl::ConnectionSurfaceMap::insert(mf::SurfaceId surface_id, std::shared_ptr<MirWindow> const& surface) |
1158 | +======= |
1159 | +void mcl::ConnectionSurfaceMap::reserve(mf::SurfaceId surface_id) |
1160 | +{ |
1161 | + std::lock_guard<decltype(reserved_guard)> lock{reserved_guard}; |
1162 | + surface_reservations[surface_id] = {}; |
1163 | +} |
1164 | + |
1165 | + |
1166 | + |
1167 | +void mcl::ConnectionSurfaceMap::insert(mf::SurfaceId surface_id, std::shared_ptr<MirSurface> const& surface) |
1168 | +>>>>>>> MERGE-SOURCE |
1169 | { |
1170 | std::lock_guard<decltype(guard)> lk(guard); |
1171 | + std::lock_guard<decltype(reserved_guard)> lock{reserved_guard}; |
1172 | + for (auto& func : surface_reservations[surface_id]) |
1173 | + { |
1174 | + delayed_queue->enqueue( |
1175 | + [this, surface_id, exec = std::move(func)]() |
1176 | + { |
1177 | + std::shared_lock<decltype(guard)> lk(guard); |
1178 | + auto const it = surfaces.find(surface_id); |
1179 | + if (it != surfaces.end()) |
1180 | + { |
1181 | + auto const surface = it->second; |
1182 | + lk.unlock(); |
1183 | + exec(surface.get()); |
1184 | + } |
1185 | + }); |
1186 | + } |
1187 | + surface_reservations.erase(surface_id); |
1188 | surfaces[surface_id] = surface; |
1189 | } |
1190 | |
1191 | |
1192 | === modified file 'src/client/connection_surface_map.h' |
1193 | --- src/client/connection_surface_map.h 2017-03-14 04:41:33 +0000 |
1194 | +++ src/client/connection_surface_map.h 2017-03-28 00:17:49 +0000 |
1195 | @@ -23,19 +23,43 @@ |
1196 | |
1197 | #include <shared_mutex> |
1198 | #include <unordered_map> |
1199 | +#include <vector> |
1200 | |
1201 | class MirPresentationChain; |
1202 | class MirRenderSurface; |
1203 | namespace mir |
1204 | { |
1205 | +namespace dispatch |
1206 | +{ |
1207 | +class ActionQueue; |
1208 | +} |
1209 | namespace client |
1210 | { |
1211 | class MirBuffer; |
1212 | class ConnectionSurfaceMap : public SurfaceMap |
1213 | { |
1214 | public: |
1215 | +<<<<<<< TREE |
1216 | virtual std::shared_ptr<MirWindow> surface(frontend::SurfaceId) const override; |
1217 | void insert(frontend::SurfaceId surface_id, std::shared_ptr<MirWindow> const& surface); |
1218 | +======= |
1219 | + ConnectionSurfaceMap(std::shared_ptr<dispatch::ActionQueue> delayed_queue); |
1220 | + |
1221 | + void with_surface_do(frontend::SurfaceId surface_id, std::function<void(MirSurface*)> const& exec) const override; |
1222 | + /** |
1223 | + * Notify the surface map that a surface will be constructed. |
1224 | + * |
1225 | + * After this call, calls to with_surface_do(surface_id, functor) will succeed, but defer execution |
1226 | + * of functor until a subsequent call to insert(surface_id, surf). |
1227 | + * |
1228 | + * Any functor queued will be executed on the delayed queue, not in the stack of |
1229 | + * the insert() call. |
1230 | + * |
1231 | + * \param [in] surface_id ID of the surface about to be created. |
1232 | + */ |
1233 | + void reserve(frontend::SurfaceId surface_id); |
1234 | + void insert(frontend::SurfaceId surface_id, std::shared_ptr<MirSurface> const& surface); |
1235 | +>>>>>>> MERGE-SOURCE |
1236 | void erase(frontend::SurfaceId surface_id); |
1237 | |
1238 | virtual std::shared_ptr<MirBufferStream> stream(frontend::BufferStreamId) const override; |
1239 | @@ -57,8 +81,16 @@ |
1240 | std::shared_ptr<MirRenderSurface> render_surface(void* render_surface_key) const; |
1241 | #pragma GCC diagnostic pop |
1242 | private: |
1243 | + std::shared_ptr<dispatch::ActionQueue> const delayed_queue; |
1244 | + |
1245 | std::shared_timed_mutex mutable guard; |
1246 | +<<<<<<< TREE |
1247 | std::unordered_map<frontend::SurfaceId, std::shared_ptr<MirWindow>> surfaces; |
1248 | +======= |
1249 | + std::unordered_map<frontend::SurfaceId, std::shared_ptr<MirSurface>> surfaces; |
1250 | + std::mutex mutable reserved_guard; |
1251 | + std::unordered_map<frontend::SurfaceId, std::vector<std::function<void(MirSurface*)>>> mutable surface_reservations; |
1252 | +>>>>>>> MERGE-SOURCE |
1253 | std::shared_timed_mutex mutable stream_guard; |
1254 | std::unordered_map<frontend::BufferStreamId, std::shared_ptr<MirBufferStream>> streams; |
1255 | std::unordered_map<frontend::BufferStreamId, std::shared_ptr<MirPresentationChain>> chains; |
1256 | |
1257 | === added file 'src/client/default_client_buffer_stream_factory.cpp.THIS' |
1258 | --- src/client/default_client_buffer_stream_factory.cpp.THIS 1970-01-01 00:00:00 +0000 |
1259 | +++ src/client/default_client_buffer_stream_factory.cpp.THIS 2017-03-28 00:17:49 +0000 |
1260 | @@ -0,0 +1,87 @@ |
1261 | +/* |
1262 | + * Copyright © 2015 Canonical Ltd. |
1263 | + * |
1264 | + * This program is free software: you can redistribute it and/or modify it |
1265 | + * under the terms of the GNU Lesser General Public License version 3, |
1266 | + * as published by the Free Software Foundation. |
1267 | + * |
1268 | + * This program is distributed in the hope that it will be useful, |
1269 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1270 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1271 | + * GNU Lesser General Public License for more details. |
1272 | + * |
1273 | + * You should have received a copy of the GNU Lesser General Public License |
1274 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1275 | + * |
1276 | + * Authored by: Robert Carr <robert.carr@canonical.com> |
1277 | + */ |
1278 | +#include "default_client_buffer_stream_factory.h" |
1279 | +#include "buffer_stream.h" |
1280 | +#include "perf_report.h" |
1281 | +#include "logging/perf_report.h" |
1282 | +#include "lttng/perf_report.h" |
1283 | + |
1284 | +namespace mcl = mir::client; |
1285 | +namespace ml = mir::logging; |
1286 | +namespace mp = mir::protobuf; |
1287 | + |
1288 | +namespace |
1289 | +{ |
1290 | + |
1291 | +std::shared_ptr<mcl::PerfReport> |
1292 | +make_perf_report(std::shared_ptr<ml::Logger> const& logger) |
1293 | +{ |
1294 | + // TODO: It seems strange that this directly uses getenv |
1295 | + const char* report_target = getenv("MIR_CLIENT_PERF_REPORT"); |
1296 | + if (report_target && !strncmp(report_target, "log", strlen(report_target))) |
1297 | + { |
1298 | + return std::make_shared<mcl::logging::PerfReport>(logger); |
1299 | + } |
1300 | + else if (report_target && !strncmp(report_target, "lttng", strlen(report_target))) |
1301 | + { |
1302 | + return std::make_shared<mcl::lttng::PerfReport>(); |
1303 | + } |
1304 | + else |
1305 | + { |
1306 | + return std::make_shared<mcl::NullPerfReport>(); |
1307 | + } |
1308 | +} |
1309 | + |
1310 | +} |
1311 | + |
1312 | +mcl::DefaultClientBufferStreamFactory::DefaultClientBufferStreamFactory( |
1313 | + std::shared_ptr<mcl::ClientPlatform> const& client_platform, |
1314 | + std::shared_ptr<ml::Logger> const& logger) |
1315 | + : client_platform(client_platform), |
1316 | + logger(logger) |
1317 | +{ |
1318 | +} |
1319 | + |
1320 | +std::shared_ptr<mcl::ClientBufferStream> mcl::DefaultClientBufferStreamFactory::make_consumer_stream( |
1321 | + MirConnection* allocating_connection, |
1322 | + mp::DisplayServer& server, |
1323 | + mp::BufferStream const& protobuf_bs, |
1324 | + std::string const& surface_name) |
1325 | +{ |
1326 | + return std::make_shared<mcl::BufferStream>(allocating_connection, server, mcl::BufferStreamMode::Consumer, client_platform, protobuf_bs, make_perf_report(logger), surface_name); |
1327 | +} |
1328 | + |
1329 | +std::shared_ptr<mcl::ClientBufferStream> mcl::DefaultClientBufferStreamFactory::make_producer_stream( |
1330 | + MirConnection* allocating_connection, |
1331 | + mp::DisplayServer& server, |
1332 | + mp::BufferStream const& protobuf_bs, |
1333 | + std::string const& surface_name) |
1334 | +{ |
1335 | + return std::make_shared<mcl::BufferStream>(allocating_connection, server, mcl::BufferStreamMode::Producer, client_platform, protobuf_bs, make_perf_report(logger), surface_name); |
1336 | +} |
1337 | + |
1338 | + |
1339 | +mcl::ClientBufferStream* mcl::DefaultClientBufferStreamFactory::make_producer_stream( |
1340 | + MirConnection* allocating_connection, |
1341 | + mp::DisplayServer& server, |
1342 | + mp::BufferStreamParameters const& params, |
1343 | + mir_buffer_stream_callback callback, |
1344 | + void* context) |
1345 | +{ |
1346 | + return new mcl::BufferStream(allocating_connection, server, client_platform, params, make_perf_report(logger), callback, context); |
1347 | +} |
1348 | |
1349 | === added file 'src/client/default_client_buffer_stream_factory.h.THIS' |
1350 | --- src/client/default_client_buffer_stream_factory.h.THIS 1970-01-01 00:00:00 +0000 |
1351 | +++ src/client/default_client_buffer_stream_factory.h.THIS 2017-03-28 00:17:49 +0000 |
1352 | @@ -0,0 +1,70 @@ |
1353 | +/* |
1354 | + * Copyright © 2015 Canonical Ltd. |
1355 | + * |
1356 | + * This program is free software: you can redistribute it and/or modify it |
1357 | + * under the terms of the GNU Lesser General Public License version 3, |
1358 | + * as published by the Free Software Foundation. |
1359 | + * |
1360 | + * This program is distributed in the hope that it will be useful, |
1361 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1362 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1363 | + * GNU Lesser General Public License for more details. |
1364 | + * |
1365 | + * You should have received a copy of the GNU Lesser General Public License |
1366 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1367 | + * |
1368 | + * Authored by: Robert Carr <robert.carr@canonical.com> |
1369 | + */ |
1370 | + |
1371 | +#ifndef MIR_CLIENT_DEFAULT_CLIENT_BUFFER_STREAM_FACTORY_H_ |
1372 | +#define MIR_CLIENT_DEFAULT_CLIENT_BUFFER_STREAM_FACTORY_H_ |
1373 | + |
1374 | +#include "client_buffer_stream_factory.h" |
1375 | + |
1376 | +class MirConnection; |
1377 | + |
1378 | +namespace mir |
1379 | +{ |
1380 | +namespace logging |
1381 | +{ |
1382 | +class Logger; |
1383 | +} |
1384 | +namespace client |
1385 | +{ |
1386 | +class ClientBufferFactory; |
1387 | +class ClientPlatform; |
1388 | + |
1389 | +class DefaultClientBufferStreamFactory : public ClientBufferStreamFactory |
1390 | +{ |
1391 | +public: |
1392 | + DefaultClientBufferStreamFactory( |
1393 | + std::shared_ptr<ClientPlatform> const& native_window_factory, |
1394 | + std::shared_ptr<logging::Logger> const& logger); |
1395 | + virtual ~DefaultClientBufferStreamFactory() = default; |
1396 | + |
1397 | + std::shared_ptr<ClientBufferStream> make_consumer_stream( |
1398 | + MirConnection* allocating_connection, |
1399 | + protobuf::DisplayServer& server, |
1400 | + protobuf::BufferStream const& protobuf_bs, |
1401 | + std::string const& surface_name) override; |
1402 | + std::shared_ptr<ClientBufferStream> make_producer_stream( |
1403 | + MirConnection* allocating_connection, |
1404 | + protobuf::DisplayServer& server, |
1405 | + protobuf::BufferStream const& protobuf_bs, |
1406 | + std::string const& surface_name) override; |
1407 | + |
1408 | + ClientBufferStream* make_producer_stream( |
1409 | + MirConnection* allocating_connection, |
1410 | + protobuf::DisplayServer& server, |
1411 | + protobuf::BufferStreamParameters const& params, |
1412 | + mir_buffer_stream_callback callback, void* context) override; |
1413 | + |
1414 | +private: |
1415 | + std::shared_ptr<ClientPlatform> const client_platform; |
1416 | + std::shared_ptr<logging::Logger> const logger; |
1417 | + |
1418 | +}; |
1419 | +} |
1420 | +} |
1421 | + |
1422 | +#endif // MIR_CLIENT_DEFAULT_CLIENT_BUFFER_STREAM_FACTORY_H_ |
1423 | |
1424 | === modified file 'src/client/default_connection_configuration.cpp' |
1425 | --- src/client/default_connection_configuration.cpp 2017-02-15 14:45:41 +0000 |
1426 | +++ src/client/default_connection_configuration.cpp 2017-03-28 00:17:49 +0000 |
1427 | @@ -37,8 +37,10 @@ |
1428 | #include "probing_client_platform_factory.h" |
1429 | #include "mir_event_distributor.h" |
1430 | #include "buffer_factory.h" |
1431 | +#include "mir/dispatch/action_queue.h" |
1432 | |
1433 | namespace mcl = mir::client; |
1434 | +namespace md = mir::dispatch; |
1435 | |
1436 | namespace |
1437 | { |
1438 | @@ -53,12 +55,23 @@ |
1439 | { |
1440 | } |
1441 | |
1442 | +std::shared_ptr<md::ActionQueue> |
1443 | +mcl::DefaultConnectionConfiguration::the_delayed_queue() |
1444 | +{ |
1445 | + return delayed_queue( |
1446 | + []() |
1447 | + { |
1448 | + return std::make_shared<md::ActionQueue>(); |
1449 | + }); |
1450 | +} |
1451 | + |
1452 | std::shared_ptr<mcl::ConnectionSurfaceMap> |
1453 | mcl::DefaultConnectionConfiguration::the_surface_map() |
1454 | { |
1455 | - return surface_map([] |
1456 | + return surface_map( |
1457 | + [this]() |
1458 | { |
1459 | - return std::make_shared<mcl::ConnectionSurfaceMap>(); |
1460 | + return std::make_shared<mcl::ConnectionSurfaceMap>(the_delayed_queue()); |
1461 | }); |
1462 | } |
1463 | |
1464 | |
1465 | === modified file 'src/client/default_connection_configuration.h' |
1466 | --- src/client/default_connection_configuration.h 2017-02-15 14:45:41 +0000 |
1467 | +++ src/client/default_connection_configuration.h 2017-03-28 00:17:49 +0000 |
1468 | @@ -50,6 +50,7 @@ |
1469 | public: |
1470 | DefaultConnectionConfiguration(std::string const& socket_file); |
1471 | |
1472 | + std::shared_ptr<dispatch::ActionQueue> the_delayed_queue() override; |
1473 | std::shared_ptr<ConnectionSurfaceMap> the_surface_map() override; |
1474 | std::shared_ptr<mir::client::rpc::MirBasicRpcChannel> the_rpc_channel() override; |
1475 | std::shared_ptr<mir::logging::Logger> the_logger() override; |
1476 | @@ -69,6 +70,7 @@ |
1477 | virtual std::shared_ptr<input::receiver::InputReceiverReport> the_input_receiver_report(); |
1478 | |
1479 | protected: |
1480 | + CachedPtr<dispatch::ActionQueue> delayed_queue; |
1481 | CachedPtr<mir::client::rpc::MirBasicRpcChannel> rpc_channel; |
1482 | CachedPtr<mir::logging::Logger> logger; |
1483 | CachedPtr<ClientPlatformFactory> client_platform_factory; |
1484 | |
1485 | === modified file 'src/client/error_render_surface.cpp' |
1486 | --- src/client/error_render_surface.cpp 2017-01-18 02:29:37 +0000 |
1487 | +++ src/client/error_render_surface.cpp 2017-03-28 00:17:49 +0000 |
1488 | @@ -54,10 +54,7 @@ |
1489 | return false; |
1490 | } |
1491 | |
1492 | -MirBufferStream* mcl::ErrorRenderSurface::get_buffer_stream( |
1493 | - int /*width*/, int /*height*/, |
1494 | - MirPixelFormat /*format*/, |
1495 | - MirBufferUsage /*buffer_usage*/) |
1496 | +void mcl::ErrorRenderSurface::get_buffer_stream(int, int, MirPixelFormat, MirBufferUsage, mir_buffer_stream_callback, void*) |
1497 | { |
1498 | BOOST_THROW_EXCEPTION(std::runtime_error(error)); |
1499 | } |
1500 | |
1501 | === modified file 'src/client/error_render_surface.h' |
1502 | --- src/client/error_render_surface.h 2017-03-10 19:47:57 +0000 |
1503 | +++ src/client/error_render_surface.h 2017-03-28 00:17:49 +0000 |
1504 | @@ -39,10 +39,13 @@ |
1505 | void set_size(mir::geometry::Size) override; |
1506 | bool valid() const override; |
1507 | char const* get_error_message() const override; |
1508 | - MirBufferStream* get_buffer_stream( |
1509 | - int width, int height, |
1510 | + void get_buffer_stream( |
1511 | + int width, |
1512 | + int height, |
1513 | MirPixelFormat format, |
1514 | - MirBufferUsage buffer_usage) override; |
1515 | + MirBufferUsage buffer_usage, |
1516 | + mir_buffer_stream_callback callback, |
1517 | + void* context) override; |
1518 | MirPresentationChain* get_presentation_chain() override; |
1519 | private: |
1520 | std::string const error; |
1521 | |
1522 | === modified file 'src/client/mir_buffer_stream_api.cpp' |
1523 | --- src/client/mir_buffer_stream_api.cpp 2017-01-24 07:37:03 +0000 |
1524 | +++ src/client/mir_buffer_stream_api.cpp 2017-03-28 00:17:49 +0000 |
1525 | @@ -30,25 +30,14 @@ |
1526 | #include "mir/uncaught.h" |
1527 | #include "mir/require.h" |
1528 | |
1529 | +#include "synchronous_helper.h" |
1530 | + |
1531 | #include <stdexcept> |
1532 | #include <boost/throw_exception.hpp> |
1533 | |
1534 | namespace mcl = mir::client; |
1535 | namespace mp = mir::protobuf; |
1536 | |
1537 | -namespace |
1538 | -{ |
1539 | -// assign_result is compatible with all 2-parameter callbacks |
1540 | -void assign_result(void* result, void** context) |
1541 | -{ |
1542 | - if (context) |
1543 | - *context = result; |
1544 | -} |
1545 | - |
1546 | -} |
1547 | - |
1548 | - |
1549 | - |
1550 | MirWaitHandle* mir_connection_create_buffer_stream(MirConnection *connection, |
1551 | int width, int height, |
1552 | MirPixelFormat format, |
1553 | @@ -72,9 +61,20 @@ |
1554 | MirBufferUsage buffer_usage) |
1555 | try |
1556 | { |
1557 | +<<<<<<< TREE |
1558 | MirBufferStream *stream = nullptr; |
1559 | mir_connection_create_buffer_stream(connection, width, height, format, buffer_usage, |
1560 | reinterpret_cast<MirBufferStreamCallback>(assign_result), &stream)->wait_for_all(); |
1561 | +======= |
1562 | + MirBufferStream* stream = nullptr; |
1563 | + make_synchronous_call( |
1564 | + connection, |
1565 | + mir_connection_create_buffer_stream, |
1566 | + connection, |
1567 | + width, height, format, buffer_usage, |
1568 | + &assign_result<MirBufferStream>, |
1569 | + &stream); |
1570 | +>>>>>>> MERGE-SOURCE |
1571 | return stream; |
1572 | } |
1573 | catch (std::exception const& ex) |
1574 | @@ -94,7 +94,12 @@ |
1575 | |
1576 | void mir_buffer_stream_release_sync(MirBufferStream *buffer_stream) |
1577 | { |
1578 | - mir_buffer_stream_release(buffer_stream, nullptr, nullptr)->wait_for_all(); |
1579 | + make_synchronous_call( |
1580 | + buffer_stream->connection(), |
1581 | + &mir_buffer_stream_release, |
1582 | + buffer_stream, |
1583 | + &assign_result<MirBufferStream>, |
1584 | + static_cast<void*>(nullptr)); |
1585 | } |
1586 | |
1587 | void mir_buffer_stream_get_current_buffer(MirBufferStream* buffer_stream, MirNativeBuffer** buffer_package_out) |
1588 | @@ -132,6 +137,7 @@ |
1589 | } |
1590 | |
1591 | void mir_buffer_stream_swap_buffers_sync(MirBufferStream* buffer_stream) |
1592 | +<<<<<<< TREE |
1593 | try |
1594 | { |
1595 | buffer_stream->swap_buffers_sync(); |
1596 | @@ -139,6 +145,15 @@ |
1597 | catch (std::exception const& ex) |
1598 | { |
1599 | MIR_LOG_UNCAUGHT_EXCEPTION(ex); |
1600 | +======= |
1601 | +{ |
1602 | + make_synchronous_call( |
1603 | + buffer_stream->connection(), |
1604 | + &mir_buffer_stream_swap_buffers, |
1605 | + buffer_stream, |
1606 | + &assign_result<MirBufferStream>, |
1607 | + static_cast<void*>(nullptr)); |
1608 | +>>>>>>> MERGE-SOURCE |
1609 | } |
1610 | |
1611 | bool mir_buffer_stream_get_graphics_region( |
1612 | |
1613 | === modified file 'src/client/mir_connection.cpp' |
1614 | --- src/client/mir_connection.cpp 2017-03-21 05:51:47 +0000 |
1615 | +++ src/client/mir_connection.cpp 2017-03-28 00:17:49 +0000 |
1616 | @@ -27,8 +27,12 @@ |
1617 | #include "mir/client_platform.h" |
1618 | #include "mir/client_platform_factory.h" |
1619 | #include "rpc/mir_basic_rpc_channel.h" |
1620 | +#include "rpc/mir_protobuf_rpc_channel.h" |
1621 | #include "mir/dispatch/dispatchable.h" |
1622 | +#include "mir/dispatch/multiplexing_dispatchable.h" |
1623 | #include "mir/dispatch/threaded_dispatcher.h" |
1624 | +#include "mir/dispatch/multiplexing_dispatchable.h" |
1625 | +#include "mir/dispatch/action_queue.h" |
1626 | #include "mir/input/input_devices.h" |
1627 | #include "connection_configuration.h" |
1628 | #include "display_configuration.h" |
1629 | @@ -53,6 +57,7 @@ |
1630 | #include "mir/logging/logger.h" |
1631 | #include "mir/platform_message.h" |
1632 | #include "mir_error.h" |
1633 | +#include "mir/require.h" |
1634 | |
1635 | #include <algorithm> |
1636 | #include <cstddef> |
1637 | @@ -63,6 +68,7 @@ |
1638 | #include <boost/throw_exception.hpp> |
1639 | |
1640 | namespace mcl = mir::client; |
1641 | +namespace mclr = mir::client::rpc; |
1642 | namespace md = mir::dispatch; |
1643 | namespace mircv = mir::input::receiver; |
1644 | namespace mev = mir::events; |
1645 | @@ -309,8 +315,13 @@ |
1646 | { |
1647 | } |
1648 | |
1649 | +MirConnection::MirConnection(mir::client::ConnectionConfiguration& conf) : |
1650 | + MirConnection(conf, DispatchType::automatic) |
1651 | +{ |
1652 | +} |
1653 | + |
1654 | MirConnection::MirConnection( |
1655 | - mir::client::ConnectionConfiguration& conf) : |
1656 | + mir::client::ConnectionConfiguration& conf, DispatchType dispatch) : |
1657 | deregisterer{this}, |
1658 | surface_map(conf.the_surface_map()), |
1659 | buffer_factory(conf.the_buffer_factory()), |
1660 | @@ -330,13 +341,26 @@ |
1661 | display_configuration(conf.the_display_configuration()), |
1662 | input_devices{conf.the_input_devices()}, |
1663 | lifecycle_control(conf.the_lifecycle_control()), |
1664 | + event_handler_register(conf.the_event_handler_register()), |
1665 | + dispatcher{std::make_shared<md::MultiplexingDispatchable>()}, |
1666 | + eventloop{dispatch == DispatchType::automatic ? |
1667 | + std::make_unique<md::ThreadedDispatcher>("RPC Dispatch", dispatcher) : |
1668 | + nullptr |
1669 | + }, |
1670 | ping_handler{conf.the_ping_handler()}, |
1671 | + pong_callback(google::protobuf::NewPermanentCallback(&google::protobuf::DoNothing)), |
1672 | + delayed_queue{conf.the_delayed_queue()}, |
1673 | error_handler{conf.the_error_handler()}, |
1674 | - event_handler_register(conf.the_event_handler_register()), |
1675 | - pong_callback(google::protobuf::NewPermanentCallback(&google::protobuf::DoNothing)), |
1676 | - eventloop{new md::ThreadedDispatcher{"RPC Thread", std::dynamic_pointer_cast<md::Dispatchable>(channel)}}, |
1677 | nbuffers(get_nbuffers_from_env()) |
1678 | { |
1679 | + dispatcher->add_watch(channel); |
1680 | + dispatcher->add_watch(delayed_queue); |
1681 | + if (eventloop) |
1682 | + { |
1683 | + // Need a second thread ensure RPC is not blocked if the delayed_queue blocks, |
1684 | + // as it does when waiting for surface creation. |
1685 | + eventloop->add_thread(); |
1686 | + } |
1687 | connect_result->set_error("connect not called"); |
1688 | { |
1689 | std::lock_guard<std::mutex> lock(connection_guard); |
1690 | @@ -419,38 +443,41 @@ |
1691 | if (request_it == surface_requests.end()) |
1692 | return; |
1693 | |
1694 | - auto surface_proto = request->response; |
1695 | - auto callback = request->cb; |
1696 | - auto context = request->context; |
1697 | + auto surface_proto = request->response; |
1698 | auto const& spec = request->spec; |
1699 | std::string name{spec.surface_name.is_set() ? |
1700 | spec.surface_name.value() : ""}; |
1701 | + surface_map->reserve(mf::SurfaceId{surface_proto->id().value()}); |
1702 | |
1703 | - std::shared_ptr<MirBufferStream> default_stream {nullptr}; |
1704 | + mcl::NoTLSFuture<std::unique_ptr<mcl::BufferStream>> default_stream; |
1705 | if (surface_proto->buffer_stream().has_id()) |
1706 | { |
1707 | try |
1708 | { |
1709 | - default_stream = std::make_shared<mcl::BufferStream>( |
1710 | + default_stream = mcl::BufferStream::create( |
1711 | this, nullptr, request->wh, server, platform, surface_map, buffer_factory, |
1712 | surface_proto->buffer_stream(), make_perf_report(logger), name, |
1713 | - mir::geometry::Size{surface_proto->width(), surface_proto->height()}, nbuffers); |
1714 | - surface_map->insert(default_stream->rpc_id(), default_stream); |
1715 | + mir::geometry::Size{surface_proto->width(), surface_proto->height()}, |
1716 | + nbuffers); |
1717 | } |
1718 | catch (std::exception const& error) |
1719 | { |
1720 | if (!surface_proto->has_error()) |
1721 | surface_proto->set_error(error.what()); |
1722 | - // Clean up surface_proto's direct fds; BufferStream has cleaned up any owned by |
1723 | - // surface_proto->buffer_stream() |
1724 | - for (auto i = 0; i < surface_proto->fd_size(); i++) |
1725 | - ::close(surface_proto->fd(i)); |
1726 | } |
1727 | } |
1728 | |
1729 | +<<<<<<< TREE |
1730 | std::shared_ptr<MirWindow> surf {nullptr}; |
1731 | +======= |
1732 | +>>>>>>> MERGE-SOURCE |
1733 | if (surface_proto->has_error() || !surface_proto->has_id()) |
1734 | { |
1735 | + // Clean up surface_proto's direct fds; BufferStream has cleaned up any owned by |
1736 | + // surface_proto->buffer_stream() |
1737 | + for (auto i = 0; i < surface_proto->fd_size(); i++) |
1738 | + ::close(surface_proto->fd(i)); |
1739 | + |
1740 | std::string reason; |
1741 | if (surface_proto->has_error()) |
1742 | reason += surface_proto->error(); |
1743 | @@ -459,19 +486,63 @@ |
1744 | if (!surface_proto->has_id()) |
1745 | reason += "Server assigned surface no id"; |
1746 | auto id = next_error_id(lock); |
1747 | +<<<<<<< TREE |
1748 | surf = std::make_shared<MirWindow>(reason, this, id, request->wh); |
1749 | +======= |
1750 | + auto surf = std::make_shared<MirSurface>(reason, this, id, request->wh); |
1751 | +>>>>>>> MERGE-SOURCE |
1752 | surface_map->insert(id, surf); |
1753 | + |
1754 | + request->cb(surf.get(), request->context); |
1755 | + request->wh->result_received(); |
1756 | + } |
1757 | + else if (default_stream.valid()) |
1758 | + { |
1759 | + default_stream.then( |
1760 | + [this, request = *request_it](auto&& resolved_stream) -> void |
1761 | + { |
1762 | + std::shared_ptr<MirSurface> surf; |
1763 | + std::shared_ptr<MirBufferStream> stream; |
1764 | + try |
1765 | + { |
1766 | + stream = resolved_stream.get(); |
1767 | + surface_map->insert(stream->rpc_id(), stream); |
1768 | + } |
1769 | + catch (std::exception const& error) |
1770 | + { |
1771 | + request->response->set_error(error.what()); |
1772 | + } |
1773 | + |
1774 | + surf = std::make_shared<MirSurface>( |
1775 | + this, |
1776 | + server, |
1777 | + &debug, |
1778 | + stream, |
1779 | + input_platform, |
1780 | + request->spec, |
1781 | + *request->response, |
1782 | + request->wh); |
1783 | + surface_map->insert(mf::SurfaceId{request->response->id().value()}, surf); |
1784 | + |
1785 | + request->cb(surf.get(), request->context); |
1786 | + request->wh->result_received(); |
1787 | + }).detach(); |
1788 | } |
1789 | else |
1790 | { |
1791 | +<<<<<<< TREE |
1792 | surf = std::make_shared<MirWindow>( |
1793 | this, server, &debug, default_stream, spec, *surface_proto, request->wh); |
1794 | +======= |
1795 | + auto surf = std::make_shared<MirSurface>( |
1796 | + this, server, &debug, nullptr, input_platform, spec, *surface_proto, request->wh); |
1797 | +>>>>>>> MERGE-SOURCE |
1798 | surface_map->insert(mf::SurfaceId{surface_proto->id().value()}, surf); |
1799 | + |
1800 | + request->cb(surf.get(), request->context); |
1801 | + request->wh->result_received(); |
1802 | } |
1803 | |
1804 | - callback(surf.get(), context); |
1805 | - request->wh->result_received(); |
1806 | - |
1807 | surface_requests.erase(request_it); |
1808 | } |
1809 | |
1810 | @@ -515,17 +586,17 @@ |
1811 | |
1812 | void MirConnection::released(StreamRelease data) |
1813 | { |
1814 | + { |
1815 | + std::unique_lock<decltype(mutex)> lk(mutex); |
1816 | + if (data.rs) |
1817 | + surface_map->erase(data.rs); |
1818 | + surface_map->erase(mf::BufferStreamId(data.rpc_id)); |
1819 | + } |
1820 | + |
1821 | if (data.callback) |
1822 | data.callback(data.stream, data.context); |
1823 | if (data.handle) |
1824 | data.handle->result_received(); |
1825 | - |
1826 | - { |
1827 | - std::unique_lock<decltype(mutex)> lk(mutex); |
1828 | - if (data.rs) |
1829 | - surface_map->erase(data.rs); |
1830 | - surface_map->erase(mf::BufferStreamId(data.rpc_id)); |
1831 | - } |
1832 | } |
1833 | |
1834 | void MirConnection::released(SurfaceRelease data) |
1835 | @@ -701,6 +772,36 @@ |
1836 | return &disconnect_wait_handle; |
1837 | } |
1838 | |
1839 | +mir::Fd MirConnection::watch_fd() const |
1840 | +{ |
1841 | + return eventloop ? mir::Fd{} : dispatcher->watch_fd(); |
1842 | +} |
1843 | + |
1844 | +void MirConnection::dispatch() |
1845 | +{ |
1846 | + mir::require(!eventloop); |
1847 | + |
1848 | + dispatcher->dispatch(md::FdEvent::readable); |
1849 | +} |
1850 | + |
1851 | +void MirConnection::add_dispatchee(std::shared_ptr<mir::dispatch::Dispatchable> const& dispatchee) |
1852 | +{ |
1853 | + dispatcher->add_watch(dispatchee); |
1854 | + if (eventloop) |
1855 | + { |
1856 | + eventloop->add_thread(); |
1857 | + } |
1858 | +} |
1859 | + |
1860 | +void MirConnection::remove_dispatchee(std::shared_ptr<mir::dispatch::Dispatchable> const& dispatchee) |
1861 | +{ |
1862 | + dispatcher->remove_watch(dispatchee); |
1863 | + if (eventloop) |
1864 | + { |
1865 | + eventloop->remove_thread(); |
1866 | + } |
1867 | +} |
1868 | + |
1869 | void MirConnection::done_platform_operation( |
1870 | MirPlatformOperationCallback callback, void* context) |
1871 | { |
1872 | @@ -880,16 +981,34 @@ |
1873 | |
1874 | try |
1875 | { |
1876 | - auto stream = std::make_shared<mcl::BufferStream>( |
1877 | - this, request->rs, request->wh, server, platform, surface_map, buffer_factory, |
1878 | - *protobuf_bs, make_perf_report(logger), std::string{}, |
1879 | - mir::geometry::Size{request->parameters.width(), request->parameters.height()}, nbuffers); |
1880 | - surface_map->insert(mf::BufferStreamId(protobuf_bs->id().value()), stream); |
1881 | - |
1882 | - if (request->mbs_callback) |
1883 | - request->mbs_callback(stream.get(), request->context); |
1884 | - |
1885 | - request->wh->result_received(); |
1886 | + auto future_stream = mcl::BufferStream::create( |
1887 | + this, |
1888 | + request->rs, |
1889 | + request->wh, |
1890 | + server, |
1891 | + platform, |
1892 | + surface_map, |
1893 | + buffer_factory, |
1894 | + *protobuf_bs, |
1895 | + make_perf_report(logger), |
1896 | + std::string{}, |
1897 | + mir::geometry::Size{request->parameters.width(), request->parameters.height()}, |
1898 | + nbuffers); |
1899 | + |
1900 | + future_stream.then( |
1901 | + [this, request](auto&& resolved_stream) -> void |
1902 | + { |
1903 | + std::shared_ptr<mcl::BufferStream> stream{resolved_stream.get()}; |
1904 | + auto& protobuf_bs = request->response; |
1905 | + |
1906 | + surface_map->insert(mf::BufferStreamId(protobuf_bs->id().value()), stream); |
1907 | + |
1908 | + request->mbs_callback( |
1909 | + static_cast<MirBufferStream*>(stream.get()), |
1910 | + request->context); |
1911 | + |
1912 | + request->wh->result_received(); |
1913 | + }).detach(); |
1914 | } |
1915 | catch (std::exception const& error) |
1916 | { |
1917 | @@ -939,17 +1058,25 @@ |
1918 | return request->wh.get(); |
1919 | } |
1920 | |
1921 | -std::shared_ptr<mir::client::BufferStream> MirConnection::create_client_buffer_stream_with_id( |
1922 | +mcl::NoTLSFuture<std::unique_ptr<mcl::BufferStream>> |
1923 | +MirConnection::create_client_buffer_stream_with_id( |
1924 | int width, int height, |
1925 | MirRenderSurface* render_surface, |
1926 | mir::protobuf::BufferStream const& a_protobuf_bs) |
1927 | { |
1928 | - auto stream = std::make_shared<mcl::BufferStream>( |
1929 | - this, render_surface, nullptr, server, platform, surface_map, buffer_factory, |
1930 | - a_protobuf_bs, make_perf_report(logger), std::string{}, |
1931 | - mir::geometry::Size{width, height}, nbuffers); |
1932 | - surface_map->insert(render_surface->stream_id(), stream); |
1933 | - return stream; |
1934 | + return mcl::BufferStream::create( |
1935 | + this, |
1936 | + render_surface, |
1937 | + nullptr, |
1938 | + server, |
1939 | + platform, |
1940 | + surface_map, |
1941 | + buffer_factory, |
1942 | + a_protobuf_bs, |
1943 | + make_perf_report(logger), |
1944 | + std::string{}, |
1945 | + mir::geometry::Size{width, height}, |
1946 | + nbuffers); |
1947 | } |
1948 | #pragma GCC diagnostic pop |
1949 | |
1950 | @@ -1322,8 +1449,15 @@ |
1951 | server.release_buffers(&request, ignored.get(), gp::NewCallback(ignore)); |
1952 | } |
1953 | |
1954 | +void MirConnection::process_next_request_first() |
1955 | +{ |
1956 | + channel->process_next_request_first(); |
1957 | +} |
1958 | + |
1959 | void MirConnection::release_render_surface_with_content( |
1960 | - void* render_surface) |
1961 | + void* render_surface, |
1962 | + mir_render_surface_callback callback, |
1963 | + void* ctx) |
1964 | { |
1965 | auto rs = surface_map->render_surface(render_surface); |
1966 | if (!rs->valid()) |
1967 | @@ -1332,13 +1466,23 @@ |
1968 | return; |
1969 | } |
1970 | |
1971 | - StreamRelease stream_release{ |
1972 | - nullptr, |
1973 | - nullptr, |
1974 | - nullptr, |
1975 | - nullptr, |
1976 | - rs->stream_id().as_value(), |
1977 | - render_surface}; |
1978 | +<<<<<<< TREE |
1979 | + StreamRelease stream_release{ |
1980 | + nullptr, |
1981 | + nullptr, |
1982 | + nullptr, |
1983 | + nullptr, |
1984 | + rs->stream_id().as_value(), |
1985 | + render_surface}; |
1986 | +======= |
1987 | + StreamRelease stream_release{ |
1988 | + reinterpret_cast<MirBufferStream*>(render_surface), |
1989 | + nullptr, |
1990 | + reinterpret_cast<mir_buffer_stream_callback>(callback), |
1991 | + ctx, |
1992 | + rs->stream_id().as_value(), |
1993 | + render_surface}; |
1994 | +>>>>>>> MERGE-SOURCE |
1995 | |
1996 | mp::BufferStreamId buffer_stream_id; |
1997 | buffer_stream_id.set_value(rs->stream_id().as_value()); |
1998 | |
1999 | === modified file 'src/client/mir_connection.h' |
2000 | --- src/client/mir_connection.h 2017-03-14 04:41:33 +0000 |
2001 | +++ src/client/mir_connection.h 2017-03-28 00:17:49 +0000 |
2002 | @@ -34,6 +34,7 @@ |
2003 | #include "mir_surface.h" |
2004 | #include "display_configuration.h" |
2005 | #include "error_handler.h" |
2006 | +#include "no_tls_future-inl.h" |
2007 | |
2008 | #include <atomic> |
2009 | #include <memory> |
2010 | @@ -42,6 +43,8 @@ |
2011 | #include <unordered_set> |
2012 | #include <unordered_map> |
2013 | |
2014 | +#include "mir/fd.h" |
2015 | + |
2016 | namespace mir |
2017 | { |
2018 | namespace input |
2019 | @@ -85,8 +88,17 @@ |
2020 | namespace dispatch |
2021 | { |
2022 | class ThreadedDispatcher; |
2023 | -} |
2024 | -} |
2025 | +class Dispatchable; |
2026 | +class MultiplexingDispatchable; |
2027 | +class ActionQueue; |
2028 | +} |
2029 | +} |
2030 | + |
2031 | +enum class DispatchType |
2032 | +{ |
2033 | + automatic, |
2034 | + manual |
2035 | +}; |
2036 | |
2037 | struct MirConnection : mir::client::ClientContext |
2038 | { |
2039 | @@ -94,6 +106,7 @@ |
2040 | MirConnection(std::string const& error_message); |
2041 | |
2042 | MirConnection(mir::client::ConnectionConfiguration& conf); |
2043 | + MirConnection(mir::client::ConnectionConfiguration &conf, DispatchType dispatch); |
2044 | ~MirConnection() noexcept; |
2045 | |
2046 | MirConnection(MirConnection const &) = delete; |
2047 | @@ -119,6 +132,12 @@ |
2048 | |
2049 | MirWaitHandle* disconnect(); |
2050 | |
2051 | + mir::Fd watch_fd() const; |
2052 | + void dispatch(); |
2053 | + |
2054 | + void add_dispatchee(std::shared_ptr<mir::dispatch::Dispatchable> const& dispatchee); |
2055 | + void remove_dispatchee(std::shared_ptr<mir::dispatch::Dispatchable> const& dispatchee); |
2056 | + |
2057 | MirWaitHandle* platform_operation( |
2058 | MirPlatformMessage const* request, |
2059 | MirPlatformOperationCallback callback, void* context) override; |
2060 | @@ -151,7 +170,7 @@ |
2061 | MirRenderSurface* render_surface, |
2062 | MirBufferStreamCallback mbs_callback, |
2063 | void *context); |
2064 | - std::shared_ptr<mir::client::BufferStream> create_client_buffer_stream_with_id( |
2065 | + mir::client::NoTLSFuture<std::unique_ptr<mir::client::BufferStream>> create_client_buffer_stream_with_id( |
2066 | int width, int height, |
2067 | MirRenderSurface* render_surface, |
2068 | mir::protobuf::BufferStream const& a_protobuf_bs); |
2069 | @@ -221,10 +240,13 @@ |
2070 | void* context) -> MirRenderSurface*; |
2071 | #pragma GCC diagnostic pop |
2072 | void release_render_surface_with_content( |
2073 | - void* render_surface); |
2074 | + void* render_surface, |
2075 | + mir_render_surface_callback callback, |
2076 | + void* ctx); |
2077 | |
2078 | void* request_interface(char const* name, int version); |
2079 | |
2080 | + void process_next_request_first(); |
2081 | private: |
2082 | //google cant have callbacks with more than 2 args |
2083 | struct SurfaceCreationRequest |
2084 | @@ -242,7 +264,7 @@ |
2085 | std::shared_ptr<MirWaitHandle> wh; |
2086 | }; |
2087 | std::vector<std::shared_ptr<SurfaceCreationRequest>> surface_requests; |
2088 | - void surface_created(SurfaceCreationRequest*); |
2089 | + void surface_created(SurfaceCreationRequest*); |
2090 | |
2091 | struct StreamCreationRequest |
2092 | { |
2093 | @@ -350,16 +372,20 @@ |
2094 | |
2095 | std::shared_ptr<mir::client::LifecycleControl> const lifecycle_control; |
2096 | |
2097 | + |
2098 | + std::shared_ptr<mir::client::EventHandlerRegister> const event_handler_register; |
2099 | + |
2100 | + std::shared_ptr<mir::dispatch::MultiplexingDispatchable> const dispatcher; |
2101 | + std::unique_ptr<mir::dispatch::ThreadedDispatcher> const eventloop; |
2102 | + |
2103 | std::shared_ptr<mir::client::PingHandler> const ping_handler; |
2104 | |
2105 | + std::unique_ptr<google::protobuf::Closure> const pong_callback; |
2106 | + |
2107 | + std::shared_ptr<mir::dispatch::ActionQueue> const delayed_queue; |
2108 | + |
2109 | std::shared_ptr<mir::client::ErrorHandler> error_handler; |
2110 | |
2111 | - std::shared_ptr<mir::client::EventHandlerRegister> const event_handler_register; |
2112 | - |
2113 | - std::unique_ptr<google::protobuf::Closure> const pong_callback; |
2114 | - |
2115 | - std::unique_ptr<mir::dispatch::ThreadedDispatcher> const eventloop; |
2116 | - |
2117 | |
2118 | struct SurfaceRelease; |
2119 | struct StreamRelease; |
2120 | |
2121 | === modified file 'src/client/mir_connection_api.cpp' |
2122 | --- src/client/mir_connection_api.cpp 2017-02-15 07:38:33 +0000 |
2123 | +++ src/client/mir_connection_api.cpp 2017-03-28 00:17:49 +0000 |
2124 | @@ -29,9 +29,11 @@ |
2125 | #include "display_configuration.h" |
2126 | #include "error_connections.h" |
2127 | #include "mir/uncaught.h" |
2128 | +#include "synchronous_helper.h" |
2129 | |
2130 | #include <cstddef> |
2131 | #include <cstring> |
2132 | +#include <poll.h> |
2133 | |
2134 | namespace mcl = mir::client; |
2135 | namespace mp = mir::protobuf; |
2136 | @@ -39,12 +41,105 @@ |
2137 | |
2138 | namespace |
2139 | { |
2140 | +<<<<<<< TREE |
2141 | // assign_result is compatible with all 2-parameter callbacks |
2142 | void assign_result(void* result, void** context) |
2143 | { |
2144 | if (context) |
2145 | *context = result; |
2146 | } |
2147 | +======= |
2148 | +class DefaultMirConnectionAPI : public mcl::MirConnectionAPI |
2149 | +{ |
2150 | +public: |
2151 | + MirWaitHandle* connect( |
2152 | + mcl::ConfigurationFactory configuration, |
2153 | + char const* socket_file, |
2154 | + char const* name, |
2155 | + mir_connected_callback callback, |
2156 | + void* context) override |
2157 | + { |
2158 | + try |
2159 | + { |
2160 | + std::string sock; |
2161 | + if (socket_file) |
2162 | + sock = socket_file; |
2163 | + else |
2164 | + { |
2165 | + auto socket_env = getenv("MIR_SOCKET"); |
2166 | + if (socket_env && socket_env[0]) |
2167 | + sock = socket_env; |
2168 | + else |
2169 | + sock = mir::default_server_socket; |
2170 | + } |
2171 | + |
2172 | + auto const conf = configuration(sock); |
2173 | + |
2174 | + auto connection = std::make_unique<MirConnection>(*conf); |
2175 | + auto const result = connection->connect(name, callback, context); |
2176 | + connection.release(); |
2177 | + return result; |
2178 | + } |
2179 | + catch (std::exception const& x) |
2180 | + { |
2181 | + MirConnection* error_connection = new MirConnection(x.what()); |
2182 | + mcl::ErrorConnections::instance().insert(error_connection); |
2183 | + callback(error_connection, context); |
2184 | + return nullptr; |
2185 | + } |
2186 | + } |
2187 | + |
2188 | + void release(MirConnection* connection) override |
2189 | + { |
2190 | + if (!mcl::ErrorConnections::instance().contains(connection)) |
2191 | + { |
2192 | + try |
2193 | + { |
2194 | + auto wait_handle = connection->disconnect(); |
2195 | + if (connection->watch_fd() != mir::Fd::invalid) |
2196 | + { |
2197 | + pollfd fd; |
2198 | + fd.fd = connection->watch_fd(); |
2199 | + fd.events = POLLIN; |
2200 | + while(wait_handle->is_pending() && (poll(&fd, 1, -1) > 0)) |
2201 | + { |
2202 | + connection->dispatch(); |
2203 | + } |
2204 | + } |
2205 | + else |
2206 | + { |
2207 | + wait_handle->wait_for_all(); |
2208 | + } |
2209 | + } |
2210 | + catch (std::exception const& ex) |
2211 | + { |
2212 | + // We're implementing a C API so no exceptions are to be |
2213 | + // propagated. And that's OK because if disconnect() fails, |
2214 | + // we don't care why. We're finished with the connection anyway. |
2215 | + |
2216 | + MIR_LOG_UNCAUGHT_EXCEPTION(ex); |
2217 | + } |
2218 | + } |
2219 | + else |
2220 | + { |
2221 | + mcl::ErrorConnections::instance().remove(connection); |
2222 | + } |
2223 | + |
2224 | + delete connection; |
2225 | + } |
2226 | + |
2227 | + mcl::ConfigurationFactory configuration_factory() override |
2228 | + { |
2229 | + return [](std::string const& socket) { |
2230 | + return std::unique_ptr<mcl::ConnectionConfiguration>{ |
2231 | + new mcl::DefaultConnectionConfiguration{socket} |
2232 | + }; |
2233 | + }; |
2234 | + } |
2235 | +}; |
2236 | + |
2237 | +DefaultMirConnectionAPI default_api; |
2238 | +>>>>>>> MERGE-SOURCE |
2239 | } |
2240 | |
2241 | MirWaitHandle* mir_connect( |
2242 | @@ -94,6 +189,7 @@ |
2243 | char const* app_name) |
2244 | { |
2245 | MirConnection* conn = nullptr; |
2246 | +<<<<<<< TREE |
2247 | auto wh = mir_connect(server, app_name, |
2248 | reinterpret_cast<MirConnectedCallback> |
2249 | (assign_result), |
2250 | @@ -104,9 +200,62 @@ |
2251 | wh->wait_for_all(); |
2252 | } |
2253 | |
2254 | +======= |
2255 | + mir_wait_for(mir_connect(server, app_name, |
2256 | + assign_result, |
2257 | + &conn)); |
2258 | +>>>>>>> MERGE-SOURCE |
2259 | return conn; |
2260 | } |
2261 | |
2262 | +MirConnection* mir_connect_with_manual_dispatch( |
2263 | + char const* server, |
2264 | + char const* app_name, |
2265 | + mir_connected_callback callback, |
2266 | + void* context) |
2267 | +{ |
2268 | + try |
2269 | + { |
2270 | + std::string sock; |
2271 | + if (server) |
2272 | + sock = server; |
2273 | + else |
2274 | + { |
2275 | + auto socket_env = getenv("MIR_SOCKET"); |
2276 | + if (socket_env) |
2277 | + sock = socket_env; |
2278 | + else |
2279 | + sock = mir::default_server_socket; |
2280 | + } |
2281 | + |
2282 | + mcl::DefaultConnectionConfiguration conf{sock}; |
2283 | + |
2284 | + std::unique_ptr<MirConnection> connection{new MirConnection(conf, DispatchType::manual)}; |
2285 | + connection->connect(app_name, callback, context); |
2286 | + return connection.release(); |
2287 | + } |
2288 | + catch (std::exception const& x) |
2289 | + { |
2290 | + MirConnection* error_connection = new MirConnection(x.what()); |
2291 | + mcl::ErrorConnections::instance().insert(error_connection); |
2292 | + callback(error_connection, context); |
2293 | + return error_connection; |
2294 | + } |
2295 | +} |
2296 | + |
2297 | +MirConnection* mir_connect_with_manual_dispatch_sync( |
2298 | + char const* server, |
2299 | + char const* app_name) |
2300 | +{ |
2301 | + MirConnection* result = nullptr; |
2302 | + |
2303 | + auto connection = mir_connect_with_manual_dispatch(server, app_name, &assign_result, &result); |
2304 | + |
2305 | + dispatch_connection_until(connection, [&result]() { return result != nullptr; }); |
2306 | + |
2307 | + return connection; |
2308 | +} |
2309 | + |
2310 | bool mir_connection_is_valid(MirConnection* connection) |
2311 | { |
2312 | return MirConnection::is_valid(connection); |
2313 | @@ -139,6 +288,16 @@ |
2314 | MIR_LOG_UNCAUGHT_EXCEPTION(ex); |
2315 | } |
2316 | |
2317 | +int mir_connection_get_event_fd(MirConnection* connection) |
2318 | +{ |
2319 | + return connection->watch_fd(); |
2320 | +} |
2321 | + |
2322 | +void mir_connection_dispatch(MirConnection* connection) |
2323 | +{ |
2324 | + connection->dispatch(); |
2325 | +} |
2326 | + |
2327 | void mir_connection_get_platform( |
2328 | MirConnection* connection, |
2329 | MirPlatformPackage* platform_package) |
2330 | |
2331 | === modified file 'src/client/mir_prompt_session_api.cpp' |
2332 | --- src/client/mir_prompt_session_api.cpp 2017-03-10 19:47:57 +0000 |
2333 | +++ src/client/mir_prompt_session_api.cpp 2017-03-28 00:17:49 +0000 |
2334 | @@ -25,6 +25,8 @@ |
2335 | #include "mir/require.h" |
2336 | #include "mir/uncaught.h" |
2337 | |
2338 | +#include "synchronous_helper.h" |
2339 | + |
2340 | #include <stdexcept> |
2341 | #include <boost/throw_exception.hpp> |
2342 | |
2343 | @@ -46,6 +48,17 @@ |
2344 | prompt_session->register_prompt_session_state_change_callback(state_change_callback, context); |
2345 | prompt_session->start(application_pid, null_callback, nullptr)->wait_for_all(); |
2346 | |
2347 | +<<<<<<< TREE |
2348 | +======= |
2349 | + make_synchronous_call( |
2350 | + connection, |
2351 | + std::mem_fn(&MirPromptSession::start), |
2352 | + prompt_session, |
2353 | + application_pid, |
2354 | + &assign_result<MirPromptSession>, |
2355 | + static_cast<void*>(nullptr)); |
2356 | + |
2357 | +>>>>>>> MERGE-SOURCE |
2358 | return prompt_session; |
2359 | } |
2360 | catch (std::exception const& ex) |
2361 | |
2362 | === modified file 'src/client/mir_render_surface_api.cpp' |
2363 | --- src/client/mir_render_surface_api.cpp 2017-03-14 04:41:33 +0000 |
2364 | +++ src/client/mir_render_surface_api.cpp 2017-03-28 00:17:49 +0000 |
2365 | @@ -163,10 +163,13 @@ |
2366 | } |
2367 | |
2368 | void mir_render_surface_release( |
2369 | - MirRenderSurface* render_surface) |
2370 | + MirRenderSurface* render_surface, |
2371 | + mir_render_surface_callback callback, |
2372 | + void* ctx) |
2373 | try |
2374 | { |
2375 | mir::require(render_surface); |
2376 | +<<<<<<< TREE |
2377 | auto connection = connection_map.connection(render_surface); |
2378 | connection_map.erase(render_surface); |
2379 | connection->release_render_surface_with_content(render_surface); |
2380 | @@ -180,17 +183,114 @@ |
2381 | MirRenderSurface* render_surface, |
2382 | int width, int height, |
2383 | MirPixelFormat format) |
2384 | -try |
2385 | -{ |
2386 | +======= |
2387 | + auto connection = connection_map.connection(static_cast<void*>(render_surface)); |
2388 | + connection_map.erase(static_cast<void*>(render_surface)); |
2389 | + connection->release_render_surface_with_content(render_surface, callback, ctx); |
2390 | +} |
2391 | +catch (std::exception const& ex) |
2392 | +{ |
2393 | + callback(render_surface, ctx); |
2394 | + MIR_LOG_UNCAUGHT_EXCEPTION(ex); |
2395 | +} |
2396 | + |
2397 | +void mir_render_surface_get_buffer_stream( |
2398 | + MirRenderSurface* render_surface, |
2399 | + int width, |
2400 | + int height, |
2401 | + MirPixelFormat format, |
2402 | + MirBufferUsage usage, |
2403 | + mir_buffer_stream_callback callback, |
2404 | + void* context) |
2405 | +try |
2406 | +{ |
2407 | + mir::require(render_surface); |
2408 | + auto connection = connection_map.connection(static_cast<void*>(render_surface)); |
2409 | + auto rs = connection->connection_surface_map()->render_surface(render_surface); |
2410 | + rs->get_buffer_stream(width, height, format, usage, callback, context); |
2411 | +} |
2412 | +catch (std::exception const& ex) |
2413 | +{ |
2414 | + MIR_LOG_UNCAUGHT_EXCEPTION(ex); |
2415 | +} |
2416 | + |
2417 | +MirBufferStream* mir_render_surface_get_buffer_stream_sync( |
2418 | + MirRenderSurface* render_surface, |
2419 | + int width, |
2420 | + int height, |
2421 | + MirPixelFormat format, |
2422 | + MirBufferUsage usage) |
2423 | +>>>>>>> MERGE-SOURCE |
2424 | +try |
2425 | +{ |
2426 | +<<<<<<< TREE |
2427 | mir::require(render_surface); |
2428 | auto connection = connection_map.connection(render_surface); |
2429 | auto rs = connection->connection_surface_map()->render_surface(render_surface); |
2430 | return rs->get_buffer_stream(width, height, format, mir_buffer_usage_software); |
2431 | +======= |
2432 | + struct BufferStreamResult |
2433 | + { |
2434 | + std::mutex lock; |
2435 | + std::condition_variable notify; |
2436 | + bool done{false}; |
2437 | + MirBufferStream* result; |
2438 | + } ready; |
2439 | + |
2440 | + mir_render_surface_get_buffer_stream( |
2441 | + render_surface, |
2442 | + width, height, |
2443 | + format, |
2444 | + usage, |
2445 | + [](MirBufferStream* stream, void* context) |
2446 | + { |
2447 | + auto result = reinterpret_cast<BufferStreamResult*>(context); |
2448 | + |
2449 | + { |
2450 | + std::lock_guard<std::mutex> lock{result->lock}; |
2451 | + result->result = stream; |
2452 | + result->done = true; |
2453 | + } |
2454 | + result->notify.notify_all(); |
2455 | + }, |
2456 | + &ready); |
2457 | + |
2458 | + std::unique_lock<std::mutex> lock{ready.lock}; |
2459 | + ready.notify.wait(lock, [&ready]() { return ready.done; }); |
2460 | + |
2461 | + return ready.result; |
2462 | +>>>>>>> MERGE-SOURCE |
2463 | } |
2464 | catch (std::exception const& ex) |
2465 | { |
2466 | MIR_LOG_UNCAUGHT_EXCEPTION(ex); |
2467 | - return nullptr; |
2468 | + std::terminate(); |
2469 | +} |
2470 | + |
2471 | +void mir_render_surface_release_sync(MirRenderSurface* render_surface) |
2472 | +{ |
2473 | + struct Waiter |
2474 | + { |
2475 | + std::condition_variable notifier; |
2476 | + std::mutex lock; |
2477 | + bool done{false}; |
2478 | + } waiter; |
2479 | + |
2480 | + mir_render_surface_release( |
2481 | + render_surface, |
2482 | + [](MirRenderSurface*, void* ctx) |
2483 | + { |
2484 | + auto waiter = reinterpret_cast<Waiter*>(ctx); |
2485 | + { |
2486 | + std::lock_guard<std::mutex> lock{waiter->lock}; |
2487 | + waiter->done = true; |
2488 | + } |
2489 | + waiter->notifier.notify_all(); |
2490 | + }, |
2491 | + &waiter); |
2492 | + |
2493 | + std::unique_lock<std::mutex> lock(waiter.lock); |
2494 | + waiter.notifier.wait(lock, [&waiter]() { return waiter.done; }); |
2495 | } |
2496 | |
2497 | MirPresentationChain* mir_render_surface_get_presentation_chain( |
2498 | |
2499 | === modified file 'src/client/mir_screencast.cpp' |
2500 | --- src/client/mir_screencast.cpp 2017-03-10 19:47:57 +0000 |
2501 | +++ src/client/mir_screencast.cpp 2017-03-28 00:17:49 +0000 |
2502 | @@ -104,8 +104,9 @@ |
2503 | { |
2504 | } |
2505 | |
2506 | -MirScreencast::MirScreencast(std::string const& error) |
2507 | - : protobuf_screencast{mcl::make_protobuf_object<mir::protobuf::Screencast>()} |
2508 | +MirScreencast::MirScreencast(MirConnection* connection, std::string const& error) |
2509 | + : connection{connection}, |
2510 | + protobuf_screencast{mcl::make_protobuf_object<mir::protobuf::Screencast>()} |
2511 | { |
2512 | protobuf_screencast->set_error(error); |
2513 | } |
2514 | @@ -178,7 +179,12 @@ |
2515 | } |
2516 | |
2517 | void MirScreencast::screencast_created( |
2518 | +<<<<<<< TREE |
2519 | MirScreencastCallback callback, void* context) |
2520 | +======= |
2521 | + mir_screencast_callback callback, |
2522 | + void* context) |
2523 | +>>>>>>> MERGE-SOURCE |
2524 | { |
2525 | if (!protobuf_screencast->has_error() && connection) |
2526 | { |
2527 | @@ -219,3 +225,8 @@ |
2528 | std::lock_guard<decltype(mutex)> lock(mutex); |
2529 | return buffer_stream.get(); |
2530 | } |
2531 | + |
2532 | +MirConnection* MirScreencast::get_connection() |
2533 | +{ |
2534 | + return connection; |
2535 | +} |
2536 | |
2537 | === modified file 'src/client/mir_screencast.h' |
2538 | --- src/client/mir_screencast.h 2017-01-24 07:37:03 +0000 |
2539 | +++ src/client/mir_screencast.h 2017-03-28 00:17:49 +0000 |
2540 | @@ -68,7 +68,7 @@ |
2541 | struct MirScreencast |
2542 | { |
2543 | public: |
2544 | - MirScreencast(std::string const& error); |
2545 | + MirScreencast(MirConnection* connection, std::string const& error); |
2546 | MirScreencast( |
2547 | MirScreencastSpec const& spec, |
2548 | mir::client::rpc::DisplayServer& server, |
2549 | @@ -85,6 +85,7 @@ |
2550 | |
2551 | MirBufferStream* get_buffer_stream(); |
2552 | |
2553 | + MirConnection* get_connection(); |
2554 | private: |
2555 | void screencast_created( |
2556 | MirScreencastCallback callback, void* context); |
2557 | |
2558 | === modified file 'src/client/mir_screencast_api.cpp' |
2559 | --- src/client/mir_screencast_api.cpp 2017-01-18 02:29:37 +0000 |
2560 | +++ src/client/mir_screencast_api.cpp 2017-03-28 00:17:49 +0000 |
2561 | @@ -25,6 +25,8 @@ |
2562 | #include "mir/require.h" |
2563 | #include "mir/uncaught.h" |
2564 | |
2565 | +#include "synchronous_helper.h" |
2566 | + |
2567 | #include <stdexcept> |
2568 | #include <boost/throw_exception.hpp> |
2569 | |
2570 | @@ -35,7 +37,18 @@ |
2571 | { |
2572 | auto& server = spec->connection->display_server(); |
2573 | auto screencast = std::make_unique<MirScreencast>(*spec, server, null_callback, nullptr); |
2574 | - screencast->creation_wait_handle()->wait_for_all(); |
2575 | + |
2576 | + if (spec->connection->watch_fd() != mir::Fd::invalid) |
2577 | + { |
2578 | + dispatch_connection_until(spec->connection, [&screencast]() |
2579 | + { |
2580 | + return !screencast->creation_wait_handle()->is_pending(); |
2581 | + }); |
2582 | + } |
2583 | + else |
2584 | + { |
2585 | + screencast->creation_wait_handle()->wait_for_all(); |
2586 | + } |
2587 | |
2588 | auto raw_screencast = screencast.get(); |
2589 | screencast.release(); |
2590 | @@ -92,7 +105,7 @@ |
2591 | catch (std::exception const& ex) |
2592 | { |
2593 | MIR_LOG_UNCAUGHT_EXCEPTION(ex); |
2594 | - return new MirScreencast(ex.what()); |
2595 | + return new MirScreencast(spec->connection, ex.what()); |
2596 | } |
2597 | |
2598 | bool mir_screencast_is_valid(MirScreencast *screencast) |
2599 | @@ -117,7 +130,11 @@ |
2600 | |
2601 | void mir_screencast_release_sync(MirScreencast* screencast) |
2602 | { |
2603 | - screencast->release(null_callback, nullptr)->wait_for_all(); |
2604 | + make_synchronous_call(screencast->get_connection(), |
2605 | + std::mem_fn(&MirScreencast::release), |
2606 | + screencast, |
2607 | + &assign_result<MirScreencast>, |
2608 | + static_cast<void*>(nullptr)); |
2609 | delete screencast; |
2610 | } |
2611 | |
2612 | |
2613 | === modified file 'src/client/mir_surface.cpp' |
2614 | --- src/client/mir_surface.cpp 2017-03-23 17:23:58 +0000 |
2615 | +++ src/client/mir_surface.cpp 2017-03-28 00:17:49 +0000 |
2616 | @@ -194,6 +194,15 @@ |
2617 | spec.event_handler.value().context); |
2618 | } |
2619 | |
2620 | +<<<<<<< TREE |
2621 | +======= |
2622 | + if (surface_proto.fd_size() > 0 && handle_event_callback) |
2623 | + { |
2624 | + input_dispatcher = input_platform->create_input_receiver(surface_proto.fd(0), keymapper, handle_event_callback); |
2625 | + connection()->add_dispatchee(input_dispatcher); |
2626 | + } |
2627 | + |
2628 | +>>>>>>> MERGE-SOURCE |
2629 | std::lock_guard<decltype(handle_mutex)> lock(handle_mutex); |
2630 | valid_surfaces.insert(this); |
2631 | |
2632 | @@ -220,7 +229,10 @@ |
2633 | |
2634 | std::lock_guard<decltype(mutex)> lock(mutex); |
2635 | |
2636 | - input_thread.reset(); |
2637 | + if (input_dispatcher) |
2638 | + { |
2639 | + connection()->remove_dispatchee(input_dispatcher); |
2640 | + } |
2641 | |
2642 | for (auto i = 0, end = surface->fd_size(); i != end; ++i) |
2643 | close(surface->fd(i)); |
2644 | @@ -466,7 +478,12 @@ |
2645 | { |
2646 | std::lock_guard<decltype(mutex)> lock(mutex); |
2647 | |
2648 | - input_thread.reset(); |
2649 | + if (input_dispatcher) |
2650 | + { |
2651 | + connection()->remove_dispatchee(input_dispatcher); |
2652 | + input_dispatcher.reset(); |
2653 | + } |
2654 | + |
2655 | handle_event_callback = [](auto){}; |
2656 | |
2657 | if (callback) |
2658 | @@ -474,6 +491,17 @@ |
2659 | handle_event_callback = std::bind(callback, this, |
2660 | std::placeholders::_1, |
2661 | context); |
2662 | +<<<<<<< TREE |
2663 | +======= |
2664 | + |
2665 | + if (surface->fd_size() > 0 && handle_event_callback) |
2666 | + { |
2667 | + input_dispatcher = input_platform->create_input_receiver(surface->fd(0), |
2668 | + keymapper, |
2669 | + handle_event_callback); |
2670 | + connection()->add_dispatchee(input_dispatcher); |
2671 | + } |
2672 | +>>>>>>> MERGE-SOURCE |
2673 | } |
2674 | } |
2675 | |
2676 | |
2677 | === modified file 'src/client/mir_surface.h' |
2678 | --- src/client/mir_surface.h 2017-03-23 17:23:58 +0000 |
2679 | +++ src/client/mir_surface.h 2017-03-28 00:17:49 +0000 |
2680 | @@ -44,7 +44,7 @@ |
2681 | { |
2682 | namespace dispatch |
2683 | { |
2684 | -class ThreadedDispatcher; |
2685 | +class Dispatchable; |
2686 | } |
2687 | namespace input |
2688 | { |
2689 | @@ -263,9 +263,13 @@ |
2690 | std::shared_ptr<mir::client::FrameClock> const frame_clock; |
2691 | |
2692 | std::function<void(MirEvent const*)> handle_event_callback; |
2693 | +<<<<<<< TREE |
2694 | std::function<void(MirWindowEvent const*)> handle_drag_and_drop_start_callback = [](auto){}; |
2695 | |
2696 | std::shared_ptr<mir::dispatch::ThreadedDispatcher> input_thread; |
2697 | +======= |
2698 | + std::shared_ptr<mir::dispatch::Dispatchable> input_dispatcher; |
2699 | +>>>>>>> MERGE-SOURCE |
2700 | |
2701 | //a bit batty, but the creation handle has to exist for as long as the MirSurface does, |
2702 | //as we don't really manage the lifetime of MirWaitHandle sensibly. |
2703 | @@ -274,7 +278,6 @@ |
2704 | MirPixelFormat format; |
2705 | MirBufferUsage usage; |
2706 | uint32_t output_id; |
2707 | - |
2708 | }; |
2709 | |
2710 | #pragma GCC diagnostic pop |
2711 | |
2712 | === modified file 'src/client/mir_surface_api.cpp' |
2713 | --- src/client/mir_surface_api.cpp 2017-03-14 04:41:33 +0000 |
2714 | +++ src/client/mir_surface_api.cpp 2017-03-28 00:17:49 +0000 |
2715 | @@ -30,6 +30,7 @@ |
2716 | #include "error_connections.h" |
2717 | #include "connection_surface_map.h" |
2718 | #include "mir/uncaught.h" |
2719 | +#include "synchronous_helper.h" |
2720 | |
2721 | #include <boost/exception/diagnostic_information.hpp> |
2722 | #include <functional> |
2723 | @@ -37,6 +38,7 @@ |
2724 | |
2725 | namespace mcl = mir::client; |
2726 | |
2727 | +<<<<<<< TREE |
2728 | namespace |
2729 | { |
2730 | MirWaitHandle* mir_configure_cursor_helper(MirWindow* window, MirCursorConfiguration const* cursor) |
2731 | @@ -895,6 +897,8 @@ |
2732 | MIR_LOG_UNCAUGHT_EXCEPTION(ex); |
2733 | } |
2734 | |
2735 | +======= |
2736 | +>>>>>>> MERGE-SOURCE |
2737 | MirSurfaceSpec* mir_connection_create_spec_for_normal_surface(MirConnection* connection, |
2738 | int width, int height, |
2739 | MirPixelFormat format) |
2740 | @@ -969,7 +973,20 @@ |
2741 | |
2742 | MirSurface* mir_surface_create_sync(MirSurfaceSpec* requested_specification) |
2743 | { |
2744 | +<<<<<<< TREE |
2745 | return mir_create_window_sync(requested_specification); |
2746 | +======= |
2747 | + MirSurface* surface = nullptr; |
2748 | + |
2749 | + make_synchronous_call( |
2750 | + requested_specification->connection, |
2751 | + &mir_surface_create, |
2752 | + requested_specification, |
2753 | + &assign_result<MirSurface>, |
2754 | + &surface); |
2755 | + |
2756 | + return surface; |
2757 | +>>>>>>> MERGE-SOURCE |
2758 | } |
2759 | |
2760 | MirWaitHandle* mir_surface_create(MirSurfaceSpec* requested_specification, |
2761 | @@ -1172,7 +1189,15 @@ |
2762 | |
2763 | void mir_surface_release_sync(MirSurface* surface) |
2764 | { |
2765 | +<<<<<<< TREE |
2766 | mir_window_release_sync(surface); |
2767 | +======= |
2768 | + make_synchronous_call(surface->connection(), |
2769 | + mir_surface_release, |
2770 | + surface, |
2771 | + &assign_result<MirSurface>, |
2772 | + static_cast<void*>(nullptr)); |
2773 | +>>>>>>> MERGE-SOURCE |
2774 | } |
2775 | |
2776 | MirSurfaceType mir_surface_get_type(MirSurface* surf) |
2777 | |
2778 | === modified file 'src/client/mir_wait_api.cpp' |
2779 | --- src/client/mir_wait_api.cpp 2014-03-31 14:36:08 +0000 |
2780 | +++ src/client/mir_wait_api.cpp 2017-03-28 00:17:49 +0000 |
2781 | @@ -30,3 +30,12 @@ |
2782 | if (wait_handle) |
2783 | wait_handle->wait_for_one(); |
2784 | } |
2785 | + |
2786 | +bool mir_wait_handle_ready(MirWaitHandle* wait_handle) |
2787 | +{ |
2788 | + if (wait_handle) |
2789 | + { |
2790 | + return !wait_handle->is_pending(); |
2791 | + } |
2792 | + return true; |
2793 | +} |
2794 | |
2795 | === modified file 'src/client/no_tls_future-inl.h' |
2796 | --- src/client/no_tls_future-inl.h 2017-01-18 02:29:37 +0000 |
2797 | +++ src/client/no_tls_future-inl.h 2017-03-28 00:17:49 +0000 |
2798 | @@ -395,6 +395,7 @@ |
2799 | NoTLSPromiseBase& operator=(NoTLSPromiseBase&& other) |
2800 | { |
2801 | state = std::move(other.state); |
2802 | + return *this; |
2803 | } |
2804 | |
2805 | NoTLSPromiseBase(NoTLSPromiseBase const&) = delete; |
2806 | |
2807 | === modified file 'src/client/render_surface.cpp' |
2808 | --- src/client/render_surface.cpp 2017-03-14 02:26:28 +0000 |
2809 | +++ src/client/render_surface.cpp 2017-03-28 00:17:49 +0000 |
2810 | @@ -25,6 +25,7 @@ |
2811 | #include "mir/client_platform.h" |
2812 | |
2813 | #include <boost/throw_exception.hpp> |
2814 | +#include <mir/require.h> |
2815 | |
2816 | namespace mcl = mir::client; |
2817 | namespace geom = mir::geometry; |
2818 | @@ -55,27 +56,46 @@ |
2819 | return mf::BufferStreamId(protobuf_bs->id().value()); |
2820 | } |
2821 | |
2822 | -MirBufferStream* mcl::RenderSurface::get_buffer_stream( |
2823 | - int width, int height, |
2824 | +void mcl::RenderSurface::get_buffer_stream( |
2825 | + int width, |
2826 | + int height, |
2827 | MirPixelFormat format, |
2828 | - MirBufferUsage buffer_usage) |
2829 | + MirBufferUsage buffer_usage, |
2830 | + mir_buffer_stream_callback callback, |
2831 | + void* context) |
2832 | { |
2833 | if (chain_from_id || stream_from_id) |
2834 | + { |
2835 | + callback(nullptr, context); |
2836 | BOOST_THROW_EXCEPTION(std::logic_error("Content already handed out")); |
2837 | + } |
2838 | |
2839 | protobuf_bs->set_pixel_format(format); |
2840 | protobuf_bs->set_buffer_usage(buffer_usage); |
2841 | - stream_from_id = connection_->create_client_buffer_stream_with_id(width, |
2842 | - height, |
2843 | - this, |
2844 | - *protobuf_bs); |
2845 | - if (buffer_usage == mir_buffer_usage_hardware) |
2846 | - { |
2847 | - platform->use_egl_native_window( |
2848 | - wrapped_native_window, dynamic_cast<EGLNativeSurface*>(stream_from_id.get())); |
2849 | - } |
2850 | - |
2851 | - return stream_from_id.get(); |
2852 | + |
2853 | + connection_->create_client_buffer_stream_with_id( |
2854 | + width, |
2855 | + height, |
2856 | + this, |
2857 | + *protobuf_bs).then( |
2858 | + [ |
2859 | + this, |
2860 | + buffer_usage, |
2861 | + callback, |
2862 | + context |
2863 | + ](auto&& resolved_future) |
2864 | + { |
2865 | + auto bs = resolved_future.get(); |
2866 | + |
2867 | + if (buffer_usage == mir_buffer_usage_hardware) |
2868 | + { |
2869 | + platform->use_egl_native_window( |
2870 | + wrapped_native_window, dynamic_cast<EGLNativeSurface*>(bs.get())); |
2871 | + } |
2872 | + |
2873 | + stream_from_id = std::move(bs); |
2874 | + callback(static_cast<MirBufferStream*>(stream_from_id.get()), context); |
2875 | + }).detach(); |
2876 | } |
2877 | |
2878 | MirPresentationChain* mcl::RenderSurface::get_presentation_chain() |
2879 | |
2880 | === modified file 'src/client/render_surface.h' |
2881 | --- src/client/render_surface.h 2017-03-10 19:47:57 +0000 |
2882 | +++ src/client/render_surface.h 2017-03-28 00:17:49 +0000 |
2883 | @@ -56,10 +56,13 @@ |
2884 | mir::frontend::BufferStreamId stream_id() const override; |
2885 | char const* get_error_message() const override; |
2886 | bool valid() const override; |
2887 | - MirBufferStream* get_buffer_stream( |
2888 | - int width, int height, |
2889 | + void get_buffer_stream( |
2890 | + int width, |
2891 | + int height, |
2892 | MirPixelFormat format, |
2893 | - MirBufferUsage buffer_usage) override; |
2894 | + MirBufferUsage buffer_usage, |
2895 | + mir_buffer_stream_callback callback, |
2896 | + void* context) override; |
2897 | MirPresentationChain* get_presentation_chain() override; |
2898 | |
2899 | private: |
2900 | |
2901 | === modified file 'src/client/rpc/make_rpc_channel.h' |
2902 | --- src/client/rpc/make_rpc_channel.h 2017-01-18 02:29:37 +0000 |
2903 | +++ src/client/rpc/make_rpc_channel.h 2017-03-28 00:17:49 +0000 |
2904 | @@ -41,6 +41,7 @@ |
2905 | { |
2906 | class MirBasicRpcChannel; |
2907 | class RpcReport; |
2908 | +class MirBasicRpcChannel; |
2909 | |
2910 | std::shared_ptr<mir::client::rpc::MirBasicRpcChannel> |
2911 | make_rpc_channel( |
2912 | |
2913 | === modified file 'src/client/rpc/mir_basic_rpc_channel.h' |
2914 | --- src/client/rpc/mir_basic_rpc_channel.h 2017-01-30 05:18:36 +0000 |
2915 | +++ src/client/rpc/mir_basic_rpc_channel.h 2017-03-28 00:17:49 +0000 |
2916 | @@ -19,6 +19,8 @@ |
2917 | #ifndef MIR_CLIENT_RPC_MIR_BASIC_RPC_CHANNEL_H_ |
2918 | #define MIR_CLIENT_RPC_MIR_BASIC_RPC_CHANNEL_H_ |
2919 | |
2920 | +#include "mir/dispatch/dispatchable.h" |
2921 | + |
2922 | #include <memory> |
2923 | #include <map> |
2924 | #include <mutex> |
2925 | @@ -105,6 +107,7 @@ |
2926 | } |
2927 | |
2928 | class MirBasicRpcChannel |
2929 | + : public mir::dispatch::Dispatchable |
2930 | { |
2931 | public: |
2932 | virtual ~MirBasicRpcChannel(); |
2933 | @@ -115,11 +118,16 @@ |
2934 | google::protobuf::MessageLite* response, |
2935 | google::protobuf::Closure* complete) = 0; |
2936 | |
2937 | +<<<<<<< TREE |
2938 | virtual void discard_future_calls() = 0; |
2939 | virtual void wait_for_outstanding_calls() = 0; |
2940 | |
2941 | +======= |
2942 | + virtual void process_next_request_first() = 0; |
2943 | +>>>>>>> MERGE-SOURCE |
2944 | protected: |
2945 | MirBasicRpcChannel(); |
2946 | + |
2947 | mir::protobuf::wire::Invocation invocation_for( |
2948 | std::string const& method_name, |
2949 | google::protobuf::MessageLite const* request, |
2950 | |
2951 | === modified file 'src/client/rpc/mir_protobuf_rpc_channel.cpp' |
2952 | --- src/client/rpc/mir_protobuf_rpc_channel.cpp 2017-03-17 17:20:09 +0000 |
2953 | +++ src/client/rpc/mir_protobuf_rpc_channel.cpp 2017-03-28 00:17:49 +0000 |
2954 | @@ -374,7 +374,7 @@ |
2955 | { |
2956 | for(auto i = 0; i < seq.buffer_request().buffer().fd_size(); i++) |
2957 | close(seq.buffer_request().buffer().fd(i)); |
2958 | - throw e; |
2959 | + throw; |
2960 | } |
2961 | } |
2962 | else |
2963 | @@ -395,13 +395,22 @@ |
2964 | // But that's a job for later... |
2965 | try |
2966 | { |
2967 | +<<<<<<< TREE |
2968 | auto e = MirEvent::deserialize(event.raw()); |
2969 | +======= |
2970 | + std::shared_ptr<MirEvent> e = mev::deserialize_event(event.raw()); |
2971 | +>>>>>>> MERGE-SOURCE |
2972 | if (e) |
2973 | { |
2974 | rpc_report->event_parsing_succeeded(*e); |
2975 | |
2976 | +<<<<<<< TREE |
2977 | int window_id = 0; |
2978 | bool is_window_event = true; |
2979 | +======= |
2980 | + auto const send_e = [e](MirSurface* surface) |
2981 | + { surface->handle_event(*e); }; |
2982 | +>>>>>>> MERGE-SOURCE |
2983 | |
2984 | switch (e->type()) |
2985 | { |
2986 | |
2987 | === modified file 'src/client/rpc/mir_protobuf_rpc_channel.h' |
2988 | --- src/client/rpc/mir_protobuf_rpc_channel.h 2017-01-30 05:18:36 +0000 |
2989 | +++ src/client/rpc/mir_protobuf_rpc_channel.h 2017-03-28 00:17:49 +0000 |
2990 | @@ -53,8 +53,7 @@ |
2991 | |
2992 | class MirProtobufRpcChannel : |
2993 | public MirBasicRpcChannel, |
2994 | - public StreamTransport::Observer, |
2995 | - public dispatch::Dispatchable |
2996 | + public StreamTransport::Observer |
2997 | { |
2998 | public: |
2999 | MirProtobufRpcChannel(std::unique_ptr<StreamTransport> transport, |
3000 | @@ -91,7 +90,7 @@ |
3001 | * |
3002 | * No messages are discarded, only delayed. |
3003 | */ |
3004 | - void process_next_request_first(); |
3005 | + void process_next_request_first() override; |
3006 | |
3007 | void call_method( |
3008 | std::string const& method_name, |
3009 | @@ -112,6 +111,7 @@ |
3010 | detail::SendBuffer header_bytes; |
3011 | detail::SendBuffer body_bytes; |
3012 | |
3013 | + |
3014 | void receive_file_descriptors(google::protobuf::MessageLite* response); |
3015 | template<class MessageType> |
3016 | void receive_any_file_descriptors_for(MessageType* response); |
3017 | |
3018 | === modified file 'src/client/symbols.map' |
3019 | --- src/client/symbols.map 2017-03-21 05:51:47 +0000 |
3020 | +++ src/client/symbols.map 2017-03-28 00:17:49 +0000 |
3021 | @@ -346,17 +346,23 @@ |
3022 | mir_connection_create_render_surface; |
3023 | mir_connection_create_render_surface_sync; |
3024 | mir_render_surface_get_buffer_stream; |
3025 | + mir_render_surface_get_buffer_stream_sync; |
3026 | mir_render_surface_get_presentation_chain; |
3027 | mir_render_surface_is_valid; |
3028 | mir_render_surface_get_error_message; |
3029 | mir_render_surface_get_size; |
3030 | mir_render_surface_set_size; |
3031 | mir_render_surface_release; |
3032 | +<<<<<<< TREE |
3033 | mir_connection_present_mode_supported; |
3034 | mir_presentation_chain_set_mode; |
3035 | mir_window_spec_add_render_surface; |
3036 | mir_window_spec_set_cursor_render_surface; |
3037 | mir_cursor_configuration_from_render_surface; |
3038 | +======= |
3039 | + mir_render_surface_release_sync; |
3040 | + mir_surface_spec_add_render_surface; |
3041 | +>>>>>>> MERGE-SOURCE |
3042 | |
3043 | #private functions needed temporarily by nested passthrough |
3044 | #should not be published along with the rest of the NBS symbols |
3045 | @@ -395,6 +401,11 @@ |
3046 | mir_input_device_state_event_time; |
3047 | mir_input_device_state_event_device_pointer_buttons; |
3048 | mir_surface_spec_set_pointer_confinement; |
3049 | + mir_connect_with_manual_dispatch; |
3050 | + mir_connect_with_manual_dispatch_sync; |
3051 | + mir_connection_get_event_fd; |
3052 | + mir_connection_dispatch; |
3053 | + mir_wait_handle_ready; |
3054 | } MIR_CLIENT_0.22; |
3055 | |
3056 | MIR_CLIENT_0.25 { # New functions in Mir 0.25 |
3057 | @@ -552,6 +563,7 @@ |
3058 | mir_window_request_persistent_id; |
3059 | mir_window_request_persistent_id_sync; |
3060 | } MIR_CLIENT_0.25; |
3061 | +<<<<<<< TREE |
3062 | |
3063 | MIR_CLIENT_0.26.1 { # New functions in Mir 0.26.1 |
3064 | global: |
3065 | @@ -616,3 +628,12 @@ |
3066 | mir_touchscreen_config_set_mapping_mode; |
3067 | mir_touchscreen_config_set_output_id; |
3068 | } MIR_CLIENT_0.26.1; |
3069 | +======= |
3070 | + |
3071 | +MIR_CLIENT_DETAIL_0.26 { |
3072 | + global: |
3073 | + extern "C++" { |
3074 | + mir::client::DefaultConnectionConfiguration::the_delayed_queue*; |
3075 | + }; |
3076 | +} MIR_CLIENT_DETAIL_0.25; |
3077 | +>>>>>>> MERGE-SOURCE |
3078 | |
3079 | === added file 'src/client/synchronous_helper.cpp' |
3080 | --- src/client/synchronous_helper.cpp 1970-01-01 00:00:00 +0000 |
3081 | +++ src/client/synchronous_helper.cpp 2017-03-28 00:17:49 +0000 |
3082 | @@ -0,0 +1,33 @@ |
3083 | +/* |
3084 | + * Copyright © 2015 Canonical Ltd. |
3085 | + * |
3086 | + * This program is free software: you can redistribute it and/or modify it |
3087 | + * under the terms of the GNU Lesser General Public License version 3, |
3088 | + * as published by the Free Software Foundation. |
3089 | + * |
3090 | + * This program is distributed in the hope that it will be useful, |
3091 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
3092 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
3093 | + * GNU Lesser General Public License for more details. |
3094 | + * |
3095 | + * You should have received a copy of the GNU Lesser General Public License |
3096 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
3097 | + * |
3098 | + * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com> |
3099 | + */ |
3100 | + |
3101 | +#include "synchronous_helper.h" |
3102 | + |
3103 | +#include <poll.h> |
3104 | + |
3105 | +void dispatch_connection_until(MirConnection* connection, std::function<bool()> predicate) |
3106 | +{ |
3107 | + pollfd fd; |
3108 | + fd.fd = connection->watch_fd(); |
3109 | + fd.events = POLLIN; |
3110 | + while(!predicate() && (poll(&fd, 1, -1) > 0)) |
3111 | + { |
3112 | + connection->dispatch(); |
3113 | + } |
3114 | +} |
3115 | + |
3116 | |
3117 | === added file 'src/client/synchronous_helper.h' |
3118 | --- src/client/synchronous_helper.h 1970-01-01 00:00:00 +0000 |
3119 | +++ src/client/synchronous_helper.h 2017-03-28 00:17:49 +0000 |
3120 | @@ -0,0 +1,160 @@ |
3121 | +/* |
3122 | + * Copyright © 2015 Canonical Ltd. |
3123 | + * |
3124 | + * This program is free software: you can redistribute it and/or modify it |
3125 | + * under the terms of the GNU Lesser General Public License version 3, |
3126 | + * as published by the Free Software Foundation. |
3127 | + * |
3128 | + * This program is distributed in the hope that it will be useful, |
3129 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
3130 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
3131 | + * GNU Lesser General Public License for more details. |
3132 | + * |
3133 | + * You should have received a copy of the GNU Lesser General Public License |
3134 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
3135 | + * |
3136 | + * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com> |
3137 | + */ |
3138 | + |
3139 | +#ifndef MIR_CLIENT_SYNCHRONOUS_H_ |
3140 | +#define MIR_CLIENT_SYNCHRONOUS_H_ |
3141 | + |
3142 | +#include "mir_connection.h" |
3143 | +#include "mir_wait_handle.h" |
3144 | + |
3145 | +#include <functional> |
3146 | +#include <type_traits> |
3147 | + |
3148 | +template<typename Result> |
3149 | +void assign_result(Result* result, void* ctx) |
3150 | +{ |
3151 | + auto assignee = reinterpret_cast<Result**>(ctx); |
3152 | + if (assignee) |
3153 | + { |
3154 | + *assignee = result; |
3155 | + } |
3156 | +} |
3157 | + |
3158 | +template<typename Callback> |
3159 | +struct SynchronousContext |
3160 | +{ |
3161 | + Callback real_callback; |
3162 | + bool complete; |
3163 | + void* userdata; |
3164 | +}; |
3165 | + |
3166 | +template<typename Callable, class Tuple, std::size_t...I> |
3167 | +void apply_substituting_last_arg( |
3168 | + Callable&& function, |
3169 | + Tuple&& args, |
3170 | + std::index_sequence<I...>, |
3171 | + void* context) |
3172 | +{ |
3173 | + return std::forward<Callable>(function)( |
3174 | + std::get<I>(std::forward<Tuple>(args))..., |
3175 | + context); |
3176 | +} |
3177 | + |
3178 | + |
3179 | +template<typename... Args> |
3180 | +void synchronous_wrapper(Args... args) |
3181 | +{ |
3182 | + std::tuple<Args...> arguments{args...}; |
3183 | + constexpr std::size_t arg_count = sizeof...(Args); |
3184 | + |
3185 | + auto wrapped_context = reinterpret_cast<SynchronousContext<void(*)(Args...)>*>(std::get<arg_count - 1>(arguments)); |
3186 | + if (wrapped_context->real_callback) |
3187 | + { |
3188 | + apply_substituting_last_arg( |
3189 | + wrapped_context->real_callback, |
3190 | + std::forward_as_tuple(args...), |
3191 | + std::make_index_sequence<arg_count - 1>(), |
3192 | + wrapped_context->userdata); |
3193 | + } |
3194 | + wrapped_context->complete = true; |
3195 | +} |
3196 | + |
3197 | + |
3198 | +template<typename Callable, typename Tuple, std::size_t...I> |
3199 | +constexpr decltype(auto) call_impl(Callable&& function, Tuple&& args, std::index_sequence<I...>) |
3200 | +{ |
3201 | + return std::forward<Callable>(function)(std::get<I>(std::forward<Tuple>((args)))...); |
3202 | +} |
3203 | + |
3204 | +template<typename Callable, typename Tuple> |
3205 | +constexpr decltype(auto) apply(Callable&& function, Tuple&& args) |
3206 | +{ |
3207 | + return call_impl( |
3208 | + std::forward<Callable>(function), |
3209 | + std::forward<Tuple>(args), |
3210 | + std::make_index_sequence<std::tuple_size<std::decay_t<Tuple>>{}>{}); |
3211 | +} |
3212 | + |
3213 | +void dispatch_connection_until(MirConnection* connection, std::function<bool()> predicate); |
3214 | + |
3215 | + |
3216 | +/** |
3217 | + * \brief Make a synchronous RPC call |
3218 | + * |
3219 | + * This wrapper takes care of manually dispatching the MirConnection if it is in |
3220 | + * manual dispatch mode, or waiting for the operation to complete if in automatic |
3221 | + * dispatch mode. |
3222 | + * |
3223 | + * Given a function mir_foo_do_thing(MirFoo* target, int arg, foo_callback callback, void* context) |
3224 | + * the correct way to call this function is |
3225 | + * make_synchronous_call(connection, |
3226 | + * &mir_foo_do_thing, |
3227 | + * target, |
3228 | + * arg, |
3229 | + * callback, |
3230 | + * static_cast<void*>(context)); |
3231 | + * |
3232 | + * The last two parameters must be the callback function and the void* to pass to that callback. |
3233 | + * The last argument must have a pointer type; NULL or nullptr must be explicitly cast to |
3234 | + * void*. |
3235 | + */ |
3236 | +template<typename Callable, typename... Args> |
3237 | +void make_synchronous_call(MirConnection* connection, |
3238 | + Callable&& function, |
3239 | + Args&&... args) |
3240 | +{ |
3241 | + static_assert( |
3242 | + std::is_same<typename std::result_of<Callable(Args...)>::type, MirWaitHandle*>::value, |
3243 | + "Second parameter must be a function that returns a MirWaitHandle*"); |
3244 | + |
3245 | + if (connection->watch_fd() != mir::Fd::invalid) |
3246 | + { |
3247 | + std::tuple<Args...> arguments{args...}; |
3248 | + constexpr int arg_count = sizeof...(Args); |
3249 | + auto callback = std::get<arg_count - 2>(arguments); |
3250 | + auto context = std::get<arg_count - 1>(arguments); |
3251 | + |
3252 | + static_assert( |
3253 | + std::is_pointer<typename std::tuple_element<arg_count - 1, std::tuple<Args...>>::type>::value, |
3254 | + "The final argument must be a pointer type"); |
3255 | + static_assert( |
3256 | + std::is_pointer<typename std::tuple_element<arg_count - 2, std::tuple<Args...>>::type>::value, |
3257 | + "The second last argument must be a function pointer"); |
3258 | + |
3259 | + SynchronousContext<decltype(callback)> wrapper_context { |
3260 | + callback, |
3261 | + false, |
3262 | + context |
3263 | + }; |
3264 | + |
3265 | + std::get<arg_count - 2>(arguments) = &synchronous_wrapper; |
3266 | + std::get<arg_count - 1>(arguments) = |
3267 | + reinterpret_cast<typename std::tuple_element<arg_count - 1, std::tuple<Args...>>::type>(&wrapper_context); |
3268 | + |
3269 | + connection->process_next_request_first(); |
3270 | + apply(std::forward<Callable>(function), arguments); |
3271 | + |
3272 | + dispatch_connection_until(connection, [&wrapper_context](){ return wrapper_context.complete; }); |
3273 | + } |
3274 | + else |
3275 | + { |
3276 | + mir_wait_for(std::forward<Callable>(function)(std::forward<Args>(args)...)); |
3277 | + } |
3278 | +} |
3279 | + |
3280 | +#endif // MIR_CLIENT_SYNCHRONOUS_H_ |
3281 | |
3282 | === added file 'src/common/dispatch/threaded_dispatcher.cpp.moved' |
3283 | --- src/common/dispatch/threaded_dispatcher.cpp.moved 1970-01-01 00:00:00 +0000 |
3284 | +++ src/common/dispatch/threaded_dispatcher.cpp.moved 2017-03-28 00:17:49 +0000 |
3285 | @@ -0,0 +1,294 @@ |
3286 | +/* |
3287 | + * Copyright © 2015 Canonical Ltd. |
3288 | + * |
3289 | + * This program is free software: you can redistribute it and/or modify it |
3290 | + * under the terms of the GNU Lesser General Public License version 3, |
3291 | + * as published by the Free Software Foundation. |
3292 | + * |
3293 | + * This program is distributed in the hope that it will be useful, |
3294 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
3295 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
3296 | + * GNU Lesser General Public License for more details. |
3297 | + * |
3298 | + * You should have received a copy of the GNU Lesser General Public License |
3299 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
3300 | + * |
3301 | + * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com> |
3302 | + */ |
3303 | + |
3304 | +#include "mir/dispatch/threaded_dispatcher.h" |
3305 | +#include "mir/dispatch/dispatchable.h" |
3306 | +#include "mir/thread_name.h" |
3307 | + |
3308 | +#include "mir/raii.h" |
3309 | +#include "mir/logging/logger.h" |
3310 | + |
3311 | +#include <fcntl.h> |
3312 | +#include <poll.h> |
3313 | +#include <unistd.h> |
3314 | +#include <system_error> |
3315 | +#include <signal.h> |
3316 | +#include <boost/exception/all.hpp> |
3317 | +#include <algorithm> |
3318 | +#include <unordered_map> |
3319 | +#include <sys/eventfd.h> |
3320 | + |
3321 | +namespace md = mir::dispatch; |
3322 | + |
3323 | +class md::ThreadedDispatcher::ThreadShutdownRequestHandler : public md::Dispatchable |
3324 | +{ |
3325 | +public: |
3326 | + ThreadShutdownRequestHandler() |
3327 | + : event_semaphore{eventfd(0, EFD_CLOEXEC | EFD_SEMAPHORE)}, |
3328 | + shutting_down{false} |
3329 | + { |
3330 | + if (event_semaphore == mir::Fd::invalid) |
3331 | + { |
3332 | + BOOST_THROW_EXCEPTION((std::system_error{errno, |
3333 | + std::system_category(), |
3334 | + "Failed to create shutdown eventfd"})); |
3335 | + } |
3336 | + } |
3337 | + |
3338 | + mir::Fd watch_fd() const override |
3339 | + { |
3340 | + return event_semaphore; |
3341 | + } |
3342 | + |
3343 | + bool dispatch(md::FdEvents events) override |
3344 | + { |
3345 | + if (events & md::FdEvent::error) |
3346 | + { |
3347 | + return false; |
3348 | + } |
3349 | + |
3350 | + eventfd_t dummy; |
3351 | + if (eventfd_read(event_semaphore, &dummy) < 0) |
3352 | + { |
3353 | + BOOST_THROW_EXCEPTION((std::system_error{errno, |
3354 | + std::system_category(), |
3355 | + "Failed to clear shutdown notification"})); |
3356 | + } |
3357 | + std::lock_guard<decltype(running_flag_guard)> lock{running_flag_guard}; |
3358 | + *running_flags.at(std::this_thread::get_id()) = false; |
3359 | + |
3360 | + return true; |
3361 | + } |
3362 | + |
3363 | + md::FdEvents relevant_events() const override |
3364 | + { |
3365 | + return md::FdEvent::readable; |
3366 | + } |
3367 | + |
3368 | + std::thread::id terminate_one_thread() |
3369 | + { |
3370 | + // First we tell a thread to die, any thread... |
3371 | + if (eventfd_write(event_semaphore, 1) < 0) |
3372 | + { |
3373 | + BOOST_THROW_EXCEPTION((std::system_error{errno, |
3374 | + std::system_category(), |
3375 | + "Failed to trigger thread shutdown"})); |
3376 | + } |
3377 | + |
3378 | + // ...now we wait for a thread to die and tell us its ID... |
3379 | + // We wait for a surprisingly long time because our threads are potentially blocked |
3380 | + // in client code that we don't control. |
3381 | + // |
3382 | + // If the client is entirely unresponsive for a whole minute, it deserves to die. |
3383 | + std::unique_lock<decltype(terminating_thread_mutex)> lock{terminating_thread_mutex}; |
3384 | + if (!thread_terminating.wait_for (lock, |
3385 | + std::chrono::seconds{60}, |
3386 | + [this]() { return !terminating_threads.empty(); })) |
3387 | + { |
3388 | + BOOST_THROW_EXCEPTION((std::runtime_error{"Thread failed to shutdown"})); |
3389 | + } |
3390 | + |
3391 | + auto killed_thread_id = terminating_threads.back(); |
3392 | + terminating_threads.pop_back(); |
3393 | + return killed_thread_id; |
3394 | + } |
3395 | + |
3396 | + void terminate_all_threads_async() |
3397 | + { |
3398 | + eventfd_t thread_count; |
3399 | + { |
3400 | + std::lock_guard<std::mutex> lock(running_flag_guard); |
3401 | + thread_count = running_flags.size(); |
3402 | + shutting_down = true; |
3403 | + } |
3404 | + if (eventfd_write(event_semaphore, thread_count) < 0) |
3405 | + { |
3406 | + BOOST_THROW_EXCEPTION((std::system_error{errno, |
3407 | + std::system_category(), |
3408 | + "Failed to trigger thread shutdown"})); |
3409 | + } |
3410 | + } |
3411 | + |
3412 | + void register_thread(bool& run_flag) |
3413 | + { |
3414 | + std::lock_guard<decltype(running_flag_guard)> lock{running_flag_guard}; |
3415 | + |
3416 | + running_flags[std::this_thread::get_id()] = &run_flag; |
3417 | + if (shutting_down) |
3418 | + { |
3419 | + if (eventfd_write(event_semaphore, 1) < 0) |
3420 | + { |
3421 | + BOOST_THROW_EXCEPTION((std::system_error{errno, |
3422 | + std::system_category(), |
3423 | + "Failed to trigger thread shutdown"})); |
3424 | + } |
3425 | + } |
3426 | + } |
3427 | + |
3428 | + void unregister_thread() |
3429 | + { |
3430 | + { |
3431 | + std::lock_guard<decltype(terminating_thread_mutex)> lock{terminating_thread_mutex}; |
3432 | + terminating_threads.push_back(std::this_thread::get_id()); |
3433 | + } |
3434 | + thread_terminating.notify_one(); |
3435 | + { |
3436 | + std::lock_guard<decltype(running_flag_guard)> lock{running_flag_guard}; |
3437 | + |
3438 | + if (running_flags.erase(std::this_thread::get_id()) != 1) |
3439 | + { |
3440 | + BOOST_THROW_EXCEPTION((std::logic_error{"Attempted to unregister a not-registered thread"})); |
3441 | + } |
3442 | + } |
3443 | + } |
3444 | + |
3445 | +private: |
3446 | + mir::Fd event_semaphore; |
3447 | + |
3448 | + std::mutex terminating_thread_mutex; |
3449 | + std::condition_variable thread_terminating; |
3450 | + std::vector<std::thread::id> terminating_threads; |
3451 | + |
3452 | + std::mutex running_flag_guard; |
3453 | + std::unordered_map<std::thread::id, bool*> running_flags; |
3454 | + bool shutting_down; |
3455 | +}; |
3456 | + |
3457 | +md::ThreadedDispatcher::ThreadedDispatcher(std::string const& name, std::shared_ptr<Dispatchable> const& dispatchee) |
3458 | + : ThreadedDispatcher(name, dispatchee, [](){ throw; }) |
3459 | +{ |
3460 | +} |
3461 | + |
3462 | +md::ThreadedDispatcher::ThreadedDispatcher(std::string const& name, |
3463 | + std::shared_ptr<md::Dispatchable> const& dispatchee, |
3464 | + std::function<void()> const& exception_handler) |
3465 | + : name_base{name}, |
3466 | + thread_exiter{std::make_shared<ThreadShutdownRequestHandler>()}, |
3467 | + dispatcher{std::make_shared<MultiplexingDispatchable>()}, |
3468 | + exception_handler{exception_handler} |
3469 | +{ |
3470 | + |
3471 | + // We rely on exactly one thread at a time getting a shutdown message |
3472 | + dispatcher->add_watch(thread_exiter, md::DispatchReentrancy::sequential); |
3473 | + |
3474 | + // But our target dispatchable is welcome to be dispatched on as many threads |
3475 | + // as desired. |
3476 | + dispatcher->add_watch(dispatchee, md::DispatchReentrancy::reentrant); |
3477 | + |
3478 | + threadpool.emplace_back(&dispatch_loop, name_base, thread_exiter, dispatcher, exception_handler); |
3479 | +} |
3480 | + |
3481 | +md::ThreadedDispatcher::~ThreadedDispatcher() noexcept |
3482 | +{ |
3483 | + std::lock_guard<decltype(thread_pool_mutex)> lock{thread_pool_mutex}; |
3484 | + |
3485 | + thread_exiter->terminate_all_threads_async(); |
3486 | + |
3487 | + for (auto& thread : threadpool) |
3488 | + { |
3489 | + if (thread.get_id() == std::this_thread::get_id()) |
3490 | + { |
3491 | + // We're being destroyed from within the dispatch callback |
3492 | + // Attempting to join the eventloop will result in a trivial deadlock. |
3493 | + // |
3494 | + // The std::thread destructor will call std::terminate() for us, let's |
3495 | + // leave a useful message. |
3496 | + mir::logging::log(mir::logging::Severity::critical, |
3497 | + "Destroying ThreadedDispatcher from within a dispatch callback. This is a programming error.", |
3498 | + "Dispatch"); |
3499 | + } |
3500 | + else |
3501 | + { |
3502 | + thread.join(); |
3503 | + } |
3504 | + } |
3505 | +} |
3506 | + |
3507 | +void md::ThreadedDispatcher::add_thread() |
3508 | +{ |
3509 | + std::lock_guard<decltype(thread_pool_mutex)> lock{thread_pool_mutex}; |
3510 | + threadpool.emplace_back(&dispatch_loop, name_base, thread_exiter, dispatcher, exception_handler); |
3511 | +} |
3512 | + |
3513 | +void md::ThreadedDispatcher::remove_thread() |
3514 | +{ |
3515 | + auto terminated_thread_id = thread_exiter->terminate_one_thread(); |
3516 | + |
3517 | + // Find that thread in our vector, join() it, then remove it. |
3518 | + std::lock_guard<decltype(thread_pool_mutex)> threadpool_lock{thread_pool_mutex}; |
3519 | + |
3520 | + auto dying_thread = std::find_if(threadpool.begin(), |
3521 | + threadpool.end(), |
3522 | + [this, &terminated_thread_id](std::thread const& candidate) |
3523 | + { |
3524 | + return candidate.get_id() == terminated_thread_id; |
3525 | + }); |
3526 | + dying_thread->join(); |
3527 | + threadpool.erase(dying_thread); |
3528 | +} |
3529 | + |
3530 | +void md::ThreadedDispatcher::dispatch_loop(std::string const& name, |
3531 | + std::shared_ptr<ThreadShutdownRequestHandler> thread_register, |
3532 | + std::shared_ptr<Dispatchable> dispatcher, |
3533 | + std::function<void()> const& exception_handler) |
3534 | +{ |
3535 | + sigset_t all_signals; |
3536 | + sigfillset(&all_signals); |
3537 | + |
3538 | + if (auto error = pthread_sigmask(SIG_BLOCK, &all_signals, NULL)) |
3539 | + BOOST_THROW_EXCEPTION((std::system_error{error, |
3540 | + std::system_category(), |
3541 | + "Failed to block signals on IO thread"})); |
3542 | + |
3543 | + mir::set_thread_name(name); |
3544 | + |
3545 | + // This does not have to be std::atomic<bool> because thread_register is guaranteed to |
3546 | + // only ever be dispatch()ed from one thread at a time. |
3547 | + bool running{true}; |
3548 | + |
3549 | + auto thread_registrar = mir::raii::paired_calls( |
3550 | + [&running, thread_register]() |
3551 | + { |
3552 | + thread_register->register_thread(running); |
3553 | + }, |
3554 | + [thread_register]() |
3555 | + { |
3556 | + thread_register->unregister_thread(); |
3557 | + }); |
3558 | + |
3559 | + try |
3560 | + { |
3561 | + struct pollfd waiter; |
3562 | + waiter.fd = dispatcher->watch_fd(); |
3563 | + waiter.events = POLL_IN; |
3564 | + while (running) |
3565 | + { |
3566 | + if (poll(&waiter, 1, -1) < 0) |
3567 | + { |
3568 | + BOOST_THROW_EXCEPTION((std::system_error{errno, |
3569 | + std::system_category(), |
3570 | + "Failed to wait for event"})); |
3571 | + } |
3572 | + dispatcher->dispatch(md::FdEvent::readable); |
3573 | + } |
3574 | + } |
3575 | + catch(...) |
3576 | + { |
3577 | + exception_handler(); |
3578 | + } |
3579 | +} |
3580 | |
3581 | === modified file 'src/include/client/mir/mir_render_surface.h' |
3582 | --- src/include/client/mir/mir_render_surface.h 2017-03-10 19:47:57 +0000 |
3583 | +++ src/include/client/mir/mir_render_surface.h 2017-03-28 00:17:49 +0000 |
3584 | @@ -32,10 +32,13 @@ |
3585 | virtual mir::geometry::Size size() const = 0; |
3586 | virtual void set_size(mir::geometry::Size) = 0; |
3587 | virtual bool valid() const = 0; |
3588 | - virtual MirBufferStream* get_buffer_stream( |
3589 | - int width, int height, |
3590 | + virtual void get_buffer_stream( |
3591 | + int width, |
3592 | + int height, |
3593 | MirPixelFormat format, |
3594 | - MirBufferUsage buffer_usage) = 0; |
3595 | + MirBufferUsage buffer_usage, |
3596 | + mir_buffer_stream_callback callback, |
3597 | + void* context) = 0; |
3598 | virtual MirPresentationChain* get_presentation_chain() = 0; |
3599 | virtual char const* get_error_message() const = 0; |
3600 | virtual ~MirRenderSurface() = default; |
3601 | |
3602 | === modified file 'src/server/scene/mediating_display_changer.cpp' |
3603 | --- src/server/scene/mediating_display_changer.cpp 2017-03-13 08:12:52 +0000 |
3604 | +++ src/server/scene/mediating_display_changer.cpp 2017-03-28 00:17:49 +0000 |
3605 | @@ -336,7 +336,7 @@ |
3606 | */ |
3607 | previously_set_alarm = std::move(preview_configuration_timeout); |
3608 | preview_configuration_timeout = nullptr; |
3609 | - currently_previewing_session = std::weak_ptr<frontend::Session>{}; |
3610 | + currently_previewing_session = std::weak_ptr<frontend::Session>{} ; |
3611 | } |
3612 | |
3613 | if (previously_set_alarm->cancel()) |
3614 | |
3615 | === modified file 'tests/acceptance-tests/CMakeLists.txt' |
3616 | --- tests/acceptance-tests/CMakeLists.txt 2017-03-15 09:30:18 +0000 |
3617 | +++ tests/acceptance-tests/CMakeLists.txt 2017-03-28 00:17:49 +0000 |
3618 | @@ -1,5 +1,13 @@ |
3619 | include(CMakeDependentOption) |
3620 | |
3621 | +<<<<<<< TREE |
3622 | +======= |
3623 | +include_directories( |
3624 | + ${CMAKE_SOURCE_DIR} |
3625 | + ${UMOCKDEV_INCLUDE_DIRS} |
3626 | +) |
3627 | + |
3628 | +>>>>>>> MERGE-SOURCE |
3629 | set( |
3630 | SOURCES |
3631 | |
3632 | |
3633 | === modified file 'tests/acceptance-tests/test_client_library.cpp' |
3634 | --- tests/acceptance-tests/test_client_library.cpp 2017-03-10 19:47:57 +0000 |
3635 | +++ tests/acceptance-tests/test_client_library.cpp 2017-03-28 00:17:49 +0000 |
3636 | @@ -20,9 +20,19 @@ |
3637 | |
3638 | #include "mir_test_framework/headless_in_process_server.h" |
3639 | #include "mir_test_framework/stub_platform_helpers.h" |
3640 | +<<<<<<< TREE |
3641 | +======= |
3642 | +#include "mir_test_framework/using_stub_client_platform.h" |
3643 | +#include "mir_test_framework/fake_input_device.h" |
3644 | +#include "mir_test_framework/stub_server_platform_factory.h" |
3645 | +>>>>>>> MERGE-SOURCE |
3646 | #include "mir_test_framework/any_surface.h" |
3647 | +#include "mir/test/fd_utils.h" |
3648 | +#include "mir/test/signal.h" |
3649 | #include "mir/test/validity_matchers.h" |
3650 | +#include "mir/test/signal.h" |
3651 | #include "src/include/common/mir/protobuf/protocol_version.h" |
3652 | +#include "mir/test/signal.h" |
3653 | |
3654 | #include "mir_protobuf.pb.h" |
3655 | |
3656 | @@ -38,10 +48,16 @@ |
3657 | #include <fcntl.h> |
3658 | |
3659 | #include <errno.h> |
3660 | +#include <mir/input/input_device_info.h> |
3661 | +#include <mir/input/device_capability.h> |
3662 | |
3663 | namespace mf = mir::frontend; |
3664 | namespace mc = mir::compositor; |
3665 | namespace mtf = mir_test_framework; |
3666 | +namespace mt = mir::test; |
3667 | +namespace mi = mir::input; |
3668 | +namespace mis = mir::input::synthesis; |
3669 | + |
3670 | namespace |
3671 | { |
3672 | #pragma GCC diagnostic push |
3673 | @@ -1120,8 +1136,371 @@ |
3674 | mir_connection_release(connection); |
3675 | } |
3676 | |
3677 | +<<<<<<< TREE |
3678 | #pragma GCC diagnostic push |
3679 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" |
3680 | +======= |
3681 | +namespace |
3682 | +{ |
3683 | +struct ThreadTrackingCallbacks |
3684 | +{ |
3685 | + ThreadTrackingCallbacks() |
3686 | + : client_thread{pthread_self()} |
3687 | + { |
3688 | + } |
3689 | + |
3690 | + static void connection_ready(MirConnection* /*connection*/, void* ctx) |
3691 | + { |
3692 | + auto data = reinterpret_cast<ThreadTrackingCallbacks*>(ctx); |
3693 | + EXPECT_EQ(pthread_self(), data->client_thread); |
3694 | + data->connection_ready_called.raise(); |
3695 | + } |
3696 | + |
3697 | + static void event_delegate(MirSurface* /*surf*/, MirEvent const* event, void* ctx) |
3698 | + { |
3699 | + auto data = reinterpret_cast<ThreadTrackingCallbacks*>(ctx); |
3700 | + |
3701 | + EXPECT_THAT(pthread_self(), Eq(data->client_thread)); |
3702 | + data->event_received.raise(); |
3703 | + if (mir_event_get_type(event) == mir_event_type_input) |
3704 | + { |
3705 | + data->input_event_received.raise(); |
3706 | + } |
3707 | + } |
3708 | + |
3709 | + static void surface_created(MirSurface* surf, void* ctx) |
3710 | + { |
3711 | + auto data = reinterpret_cast<ThreadTrackingCallbacks*>(ctx); |
3712 | + EXPECT_THAT(pthread_self(), Eq(data->client_thread)); |
3713 | + data->surf = surf; |
3714 | + |
3715 | + mir_surface_set_event_handler(data->surf, &ThreadTrackingCallbacks::event_delegate, data); |
3716 | + } |
3717 | + |
3718 | + static void swap_buffers_complete(MirBufferStream* /*stream*/, void* ctx) |
3719 | + { |
3720 | + auto data = reinterpret_cast<ThreadTrackingCallbacks*>(ctx); |
3721 | + EXPECT_EQ(pthread_self(), data->client_thread); |
3722 | + data->buffers_swapped.raise(); |
3723 | + } |
3724 | + |
3725 | + pthread_t const client_thread; |
3726 | + MirSurface* surf{nullptr}; |
3727 | + mt::Signal buffers_swapped; |
3728 | + mt::Signal connection_ready_called; |
3729 | + mt::Signal event_received; |
3730 | + mt::Signal input_event_received; |
3731 | +}; |
3732 | + |
3733 | +void pump_eventloop_until(MirConnection* connection, std::function<bool()> predicate, std::chrono::steady_clock::time_point timeout) |
3734 | +{ |
3735 | + using namespace std::literals::chrono_literals; |
3736 | + |
3737 | + auto fd = mir::Fd{mir::IntOwnedFd{mir_connection_get_event_fd(connection)}}; |
3738 | + |
3739 | + while (!predicate() && (std::chrono::steady_clock::now() < timeout)) |
3740 | + { |
3741 | + if (mt::fd_becomes_readable(fd, 10ms)) |
3742 | + { |
3743 | + mir_connection_dispatch(connection); |
3744 | + } |
3745 | + } |
3746 | + if (!predicate()) |
3747 | + { |
3748 | + BOOST_THROW_EXCEPTION((std::runtime_error{"Timeout waiting for state change"})); |
3749 | + } |
3750 | +} |
3751 | +} |
3752 | + |
3753 | +TEST_F(ClientLibrary, manual_dispatch_handles_callbacks_in_parent_thread) |
3754 | +{ |
3755 | + using namespace std::literals::chrono_literals; |
3756 | + |
3757 | + auto const test_timeout = std::chrono::steady_clock::now() + 10min; |
3758 | + |
3759 | + ThreadTrackingCallbacks data; |
3760 | + |
3761 | + auto connection = mir_connect_with_manual_dispatch(new_connection().c_str(), __PRETTY_FUNCTION__, &ThreadTrackingCallbacks::connection_ready, &data); |
3762 | + |
3763 | + ASSERT_THAT(connection, Ne(nullptr)); |
3764 | + |
3765 | + pump_eventloop_until( |
3766 | + connection, |
3767 | + [&data]() |
3768 | + { |
3769 | + return data.connection_ready_called.raised(); |
3770 | + }, |
3771 | + test_timeout); |
3772 | + |
3773 | + ASSERT_THAT(connection, IsValid()); |
3774 | + |
3775 | + auto surface_spec = mir_connection_create_spec_for_normal_surface(connection, |
3776 | + 233, 355, |
3777 | + mir_pixel_format_argb_8888); |
3778 | + auto surf_wh = mir_surface_create(surface_spec, |
3779 | + &ThreadTrackingCallbacks::surface_created, |
3780 | + &data); |
3781 | + mir_surface_spec_release(surface_spec); |
3782 | + |
3783 | + pump_eventloop_until( |
3784 | + connection, |
3785 | + [surf_wh]() |
3786 | + { |
3787 | + return mir_wait_handle_ready(surf_wh); |
3788 | + }, |
3789 | + test_timeout); |
3790 | + |
3791 | + EXPECT_THAT(data.surf, IsValid()); |
3792 | + |
3793 | + auto buffer_stream = mir_surface_get_buffer_stream(data.surf); |
3794 | + auto swap_wh = mir_buffer_stream_swap_buffers(buffer_stream, ThreadTrackingCallbacks::swap_buffers_complete, &data); |
3795 | + |
3796 | + pump_eventloop_until( |
3797 | + connection, |
3798 | + [swap_wh]() |
3799 | + { |
3800 | + return mir_wait_handle_ready(swap_wh); |
3801 | + }, |
3802 | + test_timeout); |
3803 | + EXPECT_TRUE(data.buffers_swapped.raised()); |
3804 | + |
3805 | + mir_surface_release_sync(data.surf); |
3806 | + mir_connection_release(connection); |
3807 | +} |
3808 | + |
3809 | +TEST_F(ClientLibrary, manual_dispatch_handles_events_in_parent_thread) |
3810 | +{ |
3811 | + using namespace testing; |
3812 | + using namespace std::literals::chrono_literals; |
3813 | + |
3814 | + auto const test_timeout = std::chrono::steady_clock::now() + 10min; |
3815 | + |
3816 | + auto fake_keyboard = mtf::add_fake_input_device( |
3817 | + mi::InputDeviceInfo{"keyboard", "keyboard-unique-id", mi::DeviceCapability::keyboard}); |
3818 | + |
3819 | + ThreadTrackingCallbacks data; |
3820 | + |
3821 | + connection = mir_connect_with_manual_dispatch(new_connection().c_str(), __PRETTY_FUNCTION__, &ThreadTrackingCallbacks::connection_ready, &data); |
3822 | + |
3823 | + ASSERT_THAT(connection, Ne(nullptr)); |
3824 | + |
3825 | + pump_eventloop_until( |
3826 | + connection, |
3827 | + [&data]() |
3828 | + { |
3829 | + return data.connection_ready_called.raised(); |
3830 | + }, |
3831 | + test_timeout); |
3832 | + |
3833 | + ASSERT_THAT(connection, IsValid()); |
3834 | + |
3835 | + auto surface_spec = mir_connection_create_spec_for_normal_surface(connection, |
3836 | + 233, 355, |
3837 | + mir_pixel_format_argb_8888); |
3838 | + auto surf_wh = mir_surface_create(surface_spec, |
3839 | + &ThreadTrackingCallbacks::surface_created, |
3840 | + &data); |
3841 | + mir_surface_spec_release(surface_spec); |
3842 | + |
3843 | + |
3844 | + pump_eventloop_until( |
3845 | + connection, |
3846 | + [surf_wh]() |
3847 | + { |
3848 | + return mir_wait_handle_ready(surf_wh); |
3849 | + }, |
3850 | + test_timeout); |
3851 | + |
3852 | + EXPECT_THAT(data.surf, IsValid()); |
3853 | + |
3854 | + // We need to swap buffers so that the surface is fully realised and |
3855 | + // will be a valid focus target. |
3856 | + // |
3857 | + // The shell will not focus a surface with no content. |
3858 | + auto buffer_stream = mir_surface_get_buffer_stream(data.surf); |
3859 | + mir_buffer_stream_swap_buffers_sync(buffer_stream); |
3860 | + |
3861 | + pump_eventloop_until( |
3862 | + connection, |
3863 | + [&data]() |
3864 | + { |
3865 | + return mir_surface_get_focus(data.surf) == mir_surface_focused; |
3866 | + }, |
3867 | + test_timeout); |
3868 | + |
3869 | + ASSERT_THAT(mir_surface_get_focus(data.surf), Eq(mir_surface_focused)); |
3870 | + |
3871 | + fake_keyboard->emit_event(mis::a_key_down_event()); |
3872 | + |
3873 | + pump_eventloop_until( |
3874 | + connection, |
3875 | + [&data]() |
3876 | + { |
3877 | + return data.input_event_received.raised(); |
3878 | + }, |
3879 | + test_timeout); |
3880 | + |
3881 | + mir_surface_release_sync(data.surf); |
3882 | + mir_connection_release(connection); |
3883 | +} |
3884 | + |
3885 | +namespace |
3886 | +{ |
3887 | +struct SignalData |
3888 | +{ |
3889 | + mir::test::Signal focus_received; |
3890 | + mir::test::Signal now_blocking; |
3891 | + mir::test::Signal event_received; |
3892 | + mir::test::Signal buffer_stream_destroyed; |
3893 | +}; |
3894 | + |
3895 | +void notifying_event_handler(MirSurface*, MirEvent const* ev, void* ctx) |
3896 | +{ |
3897 | + auto signals = *reinterpret_cast<std::shared_ptr<SignalData>*>(ctx); |
3898 | + // We trigger an input event once we've noticed the surface callback is blocking |
3899 | + // so we need to only raise the flag on an input event; otherwise we may spuriously |
3900 | + // fail if we receive a surface event (like the focus event) before we hit |
3901 | + // the wait in blocking_surface_callback() |
3902 | + if (mir_event_get_type(ev) == mir_event_type_input) |
3903 | + { |
3904 | + signals->event_received.raise(); |
3905 | + } |
3906 | + if (mir_event_get_type(ev) == mir_event_type_surface) |
3907 | + { |
3908 | + auto surface_event = mir_event_get_surface_event(ev); |
3909 | + if (mir_surface_event_get_attribute(surface_event) == mir_surface_attrib_focus && |
3910 | + mir_surface_event_get_attribute_value(surface_event) == mir_surface_focused) |
3911 | + { |
3912 | + signals->focus_received.raise(); |
3913 | + } |
3914 | + } |
3915 | +} |
3916 | + |
3917 | +void notify_buffer_stream_destroyed(MirBufferStream*, void* ctx) |
3918 | +{ |
3919 | + auto& signal = *reinterpret_cast<mt::Signal*>(ctx); |
3920 | + signal.raise(); |
3921 | +} |
3922 | + |
3923 | +void blocking_buffer_stream_callback(MirBufferStream* stream, void* ctx) |
3924 | +{ |
3925 | + auto signals = *reinterpret_cast<std::shared_ptr<SignalData>*>(ctx); |
3926 | + signals->now_blocking.raise(); |
3927 | + EXPECT_TRUE(signals->event_received.wait_for(std::chrono::seconds{5})); |
3928 | + mir_buffer_stream_release(stream, ¬ify_buffer_stream_destroyed, &signals->buffer_stream_destroyed); |
3929 | +} |
3930 | +} |
3931 | + |
3932 | +TEST_F(ClientLibrary, rpc_blocking_doesnt_block_event_delivery_with_auto_dispatch) |
3933 | +{ |
3934 | + using namespace testing; |
3935 | + |
3936 | + connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__); |
3937 | + |
3938 | + auto fake_keyboard = mtf::add_fake_input_device( |
3939 | + mi::InputDeviceInfo{"keyboard", "keyboard-unique-id", mi::DeviceCapability::keyboard}); |
3940 | + |
3941 | + |
3942 | + ASSERT_THAT(connection, IsValid()); |
3943 | + auto signals = std::make_shared<SignalData>(); |
3944 | + |
3945 | + auto surface_spec = mir_connection_create_spec_for_normal_surface(connection, |
3946 | + 233, 355, |
3947 | + mir_pixel_format_argb_8888); |
3948 | + mir_surface_spec_set_event_handler(surface_spec, ¬ifying_event_handler, &signals); |
3949 | + |
3950 | + auto surf = mir_surface_create_sync(surface_spec); |
3951 | + mir_surface_spec_release(surface_spec); |
3952 | + |
3953 | + ASSERT_THAT(surf, IsValid()); |
3954 | + |
3955 | + auto buffer_stream = mir_surface_get_buffer_stream(surf); |
3956 | + |
3957 | + // Ensure that the surface is focused. |
3958 | + mir_buffer_stream_swap_buffers_sync(buffer_stream); |
3959 | + ASSERT_TRUE(signals->focus_received.wait_for(std::chrono::seconds{5})); |
3960 | + |
3961 | + auto wh = mir_connection_create_buffer_stream( |
3962 | + connection, |
3963 | + 800, 600, |
3964 | + mir_pixel_format_abgr_8888, |
3965 | + mir_buffer_usage_software, |
3966 | + &blocking_buffer_stream_callback, &signals); |
3967 | + |
3968 | + EXPECT_TRUE(signals->now_blocking.wait_for(std::chrono::seconds{5})); |
3969 | + EXPECT_FALSE(signals->event_received.raised()); |
3970 | + |
3971 | + fake_keyboard->emit_event(mis::a_key_down_event()); |
3972 | + |
3973 | + EXPECT_TRUE(signals->event_received.wait_for(std::chrono::seconds{5})); |
3974 | + EXPECT_TRUE(signals->buffer_stream_destroyed.wait_for(std::chrono::seconds{5})); |
3975 | + |
3976 | + mir_wait_for(wh); |
3977 | + mir_surface_release_sync(surf); |
3978 | + mir_connection_release(connection); |
3979 | +} |
3980 | + |
3981 | +namespace |
3982 | +{ |
3983 | +void async_release_completed(MirSurface*, void* ctx) |
3984 | +{ |
3985 | + auto called = reinterpret_cast<bool*>(ctx); |
3986 | + *called = true; |
3987 | +} |
3988 | + |
3989 | +void async_creation_completed(MirSurface* surf, void* ctx) |
3990 | +{ |
3991 | + mir_surface_release(surf, &async_release_completed, ctx); |
3992 | +} |
3993 | +} |
3994 | + |
3995 | +TEST_F(ClientLibrary, sync_call_completes_before_previous_undispatched_call) |
3996 | +{ |
3997 | + using namespace std::literals::chrono_literals; |
3998 | + using namespace testing; |
3999 | + |
4000 | + auto timeout = std::chrono::steady_clock::now() + 60s; |
4001 | + |
4002 | + ThreadTrackingCallbacks data; |
4003 | + |
4004 | + auto connection = mir_connect_with_manual_dispatch(new_connection().c_str(), __PRETTY_FUNCTION__, &ThreadTrackingCallbacks::connection_ready, &data); |
4005 | + ASSERT_THAT(connection, Ne(nullptr)); |
4006 | + |
4007 | + pump_eventloop_until(connection, [connection]() { return mir_connection_is_valid(connection); }, timeout); |
4008 | + |
4009 | + bool async_call_completed{false}; |
4010 | + |
4011 | + auto surface_spec = mir_connection_create_spec_for_normal_surface(connection, |
4012 | + 233, 355, |
4013 | + mir_pixel_format_argb_8888); |
4014 | + mir_surface_create(surface_spec, &async_creation_completed, &async_call_completed); |
4015 | + |
4016 | + EXPECT_FALSE(async_call_completed); |
4017 | + auto surf = mir_surface_create_sync(surface_spec); |
4018 | + mir_surface_spec_release(surface_spec); |
4019 | + |
4020 | + EXPECT_THAT(surf, IsValid()); |
4021 | + EXPECT_FALSE(async_call_completed); |
4022 | + |
4023 | + mir_surface_release_sync(surf); |
4024 | + EXPECT_FALSE(async_call_completed); |
4025 | + |
4026 | + pump_eventloop_until(connection, [&async_call_completed]() { return async_call_completed;}, timeout); |
4027 | + |
4028 | +} |
4029 | + |
4030 | +TEST_F(ClientLibrary, can_connect_synchronously_with_manual_dispatch) |
4031 | +{ |
4032 | + using namespace testing; |
4033 | + |
4034 | + auto connection = mir_connect_with_manual_dispatch_sync(new_connection().c_str(), __PRETTY_FUNCTION__); |
4035 | + |
4036 | + EXPECT_THAT(connection, IsValid()); |
4037 | + |
4038 | + mir_connection_release(connection); |
4039 | +} |
4040 | + |
4041 | +>>>>>>> MERGE-SOURCE |
4042 | TEST_F(ClientLibrary, can_get_persistent_surface_id) |
4043 | { |
4044 | auto connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__); |
4045 | @@ -1225,6 +1604,7 @@ |
4046 | mir_buffer_stream_release_sync(stream); |
4047 | mir_connection_release(connection); |
4048 | } |
4049 | +<<<<<<< TREE |
4050 | |
4051 | TEST_F(ClientLibrary, client_api_version) |
4052 | { |
4053 | @@ -1232,3 +1612,117 @@ |
4054 | MIR_CLIENT_API_VERSION_MINOR, |
4055 | MIR_CLIENT_API_VERSION_PATCH) == mir_get_client_api_version()); |
4056 | } |
4057 | +======= |
4058 | + |
4059 | +TEST_F(ClientLibrary, synchronously_creating_buffer_stream_results_in_valid_buffer_stream) |
4060 | +{ |
4061 | + using namespace testing; |
4062 | + |
4063 | + auto connection = mir_connect_with_manual_dispatch_sync(new_connection().c_str(), __PRETTY_FUNCTION__); |
4064 | + |
4065 | + ASSERT_THAT(connection, IsValid()); |
4066 | + |
4067 | + int const width{640}, height{480}; |
4068 | + auto stream = mir_connection_create_buffer_stream_sync( |
4069 | + connection, |
4070 | + width, height, |
4071 | + mir_pixel_format_abgr_8888, |
4072 | + mir_buffer_usage_software); |
4073 | + |
4074 | + EXPECT_THAT(stream, IsValid()); |
4075 | + |
4076 | + MirGraphicsRegion region; |
4077 | + mir_buffer_stream_get_graphics_region(stream, ®ion); |
4078 | + |
4079 | + EXPECT_THAT(region.vaddr, NotNull()); |
4080 | + EXPECT_THAT(region.width, Eq(width)); |
4081 | + EXPECT_THAT(region.height, Eq(height)); |
4082 | + EXPECT_THAT(region.stride, Ge(width)); |
4083 | + EXPECT_THAT(region.pixel_format, Eq(mir_pixel_format_abgr_8888)); |
4084 | + |
4085 | + mir_buffer_stream_release_sync(stream); |
4086 | + mir_connection_release(connection); |
4087 | +} |
4088 | + |
4089 | +TEST_F(ClientLibrary, default_surface_stream_is_valid_in_created_callback) |
4090 | +{ |
4091 | + connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__); |
4092 | + ASSERT_TRUE(mir_connection_is_valid(connection)); |
4093 | + |
4094 | + auto surface_spec = mir_connection_create_spec_for_normal_surface( |
4095 | + connection, |
4096 | + 800, 600, |
4097 | + mir_pixel_format_argb_8888); |
4098 | + |
4099 | + mt::Signal done; |
4100 | + |
4101 | + mir_surface_create( |
4102 | + surface_spec, |
4103 | + [](MirSurface* surf, void* ctx) |
4104 | + { |
4105 | + auto stream = mir_surface_get_buffer_stream(surf); |
4106 | + EXPECT_THAT(stream, NotNull()); |
4107 | + EXPECT_TRUE(mir_buffer_stream_is_valid(stream)); |
4108 | + |
4109 | + MirNativeBuffer* package; |
4110 | + mir_buffer_stream_get_current_buffer(stream, &package); |
4111 | + |
4112 | + EXPECT_THAT(package, NotNull()); |
4113 | + |
4114 | + mir_surface_release( |
4115 | + surf, |
4116 | + [](MirSurface*, void* ctx) |
4117 | + { |
4118 | + auto done = reinterpret_cast<mt::Signal*>(ctx); |
4119 | + |
4120 | + done->raise(); |
4121 | + }, |
4122 | + ctx); |
4123 | + }, |
4124 | + &done); |
4125 | + mir_surface_spec_release(surface_spec); |
4126 | + |
4127 | + // ASSERT_TRUE rather than EXPECT_TRUE so that the test dies on client deadlock. |
4128 | + ASSERT_TRUE(done.wait_for(std::chrono::seconds{20})); |
4129 | + |
4130 | + mir_connection_release(connection); |
4131 | +} |
4132 | + |
4133 | +TEST_F(ClientLibrary, buffer_stream_is_valid_in_created_callback) |
4134 | +{ |
4135 | + connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__); |
4136 | + ASSERT_TRUE(mir_connection_is_valid(connection)); |
4137 | + |
4138 | + mt::Signal done; |
4139 | + |
4140 | + mir_connection_create_buffer_stream( |
4141 | + connection, |
4142 | + 800, 600, |
4143 | + mir_pixel_format_argb_8888, |
4144 | + mir_buffer_usage_software, |
4145 | + [](MirBufferStream* stream, void* ctx) |
4146 | + { |
4147 | + EXPECT_THAT(stream, IsValid()); |
4148 | + |
4149 | + MirNativeBuffer* package; |
4150 | + mir_buffer_stream_get_current_buffer(stream, &package); |
4151 | + |
4152 | + EXPECT_THAT(package, NotNull()); |
4153 | + |
4154 | + mir_buffer_stream_release( |
4155 | + stream, |
4156 | + [](MirBufferStream*, void* ctx) |
4157 | + { |
4158 | + auto done = reinterpret_cast<mt::Signal*>(ctx); |
4159 | + |
4160 | + done->raise(); |
4161 | + }, |
4162 | + ctx); |
4163 | + }, |
4164 | + &done); |
4165 | + |
4166 | + ASSERT_TRUE(done.wait_for(std::chrono::seconds{20})); |
4167 | + |
4168 | + mir_connection_release(connection); |
4169 | +} |
4170 | +>>>>>>> MERGE-SOURCE |
4171 | |
4172 | === modified file 'tests/acceptance-tests/test_client_surfaces.cpp' |
4173 | --- tests/acceptance-tests/test_client_surfaces.cpp 2017-03-14 04:41:33 +0000 |
4174 | +++ tests/acceptance-tests/test_client_surfaces.cpp 2017-03-28 00:17:49 +0000 |
4175 | @@ -28,6 +28,7 @@ |
4176 | #include "mir_test_framework/any_surface.h" |
4177 | #include "mir/test/validity_matchers.h" |
4178 | #include "mir/test/fake_shared.h" |
4179 | +#include "mir/test/signal.h" |
4180 | |
4181 | #include <gmock/gmock.h> |
4182 | #include <gtest/gtest.h> |
4183 | @@ -391,4 +392,43 @@ |
4184 | |
4185 | mir_connection_release(im_connection); |
4186 | } |
4187 | +<<<<<<< TREE |
4188 | #pragma GCC diagnostic pop |
4189 | +======= |
4190 | + |
4191 | +TEST_F(ClientSurfaces, default_buffer_stream_is_fully_constructed_in_surface_created_callback) |
4192 | +{ |
4193 | + using namespace testing; |
4194 | + using namespace std::chrono_literals; |
4195 | + |
4196 | + auto surface_spec = mir_connection_create_spec_for_normal_surface( |
4197 | + connection, |
4198 | + 800, 600, |
4199 | + mir_pixel_format_argb_8888); |
4200 | + |
4201 | + mt::Signal surface_released; |
4202 | + mir_surface_create( |
4203 | + surface_spec, |
4204 | + [](MirSurface* surf, void* ctx) |
4205 | + { |
4206 | + EXPECT_THAT(surf, IsValid()); |
4207 | + auto buffer_stream = mir_surface_get_buffer_stream(surf); |
4208 | + MirGraphicsRegion region; |
4209 | + mir_buffer_stream_get_graphics_region(buffer_stream, ®ion); |
4210 | + EXPECT_THAT(region.vaddr, NotNull()); |
4211 | + |
4212 | + mir_surface_release( |
4213 | + surf, |
4214 | + [](MirSurface*, void* ctx) |
4215 | + { |
4216 | + auto& done = *reinterpret_cast<mt::Signal*>(ctx); |
4217 | + done.raise(); |
4218 | + }, |
4219 | + ctx); |
4220 | + }, |
4221 | + &surface_released); |
4222 | + mir_surface_spec_release(surface_spec); |
4223 | + |
4224 | + EXPECT_TRUE(surface_released.wait_for(10s)); |
4225 | +} |
4226 | +>>>>>>> MERGE-SOURCE |
4227 | |
4228 | === modified file 'tests/acceptance-tests/test_render_surface.cpp' |
4229 | --- tests/acceptance-tests/test_render_surface.cpp 2017-03-10 19:47:57 +0000 |
4230 | +++ tests/acceptance-tests/test_render_surface.cpp 2017-03-28 00:17:49 +0000 |
4231 | @@ -23,11 +23,14 @@ |
4232 | #include "mir/geometry/size.h" |
4233 | #include "mir_test_framework/headless_in_process_server.h" |
4234 | #include "mir/test/validity_matchers.h" |
4235 | +#include "mir/test/signal.h" |
4236 | |
4237 | #include <gtest/gtest.h> |
4238 | #include <gmock/gmock.h> |
4239 | +#include "mir/test/signal.h" |
4240 | |
4241 | namespace mtf = mir_test_framework; |
4242 | +namespace mt = mir::test; |
4243 | namespace geom = mir::geometry; |
4244 | |
4245 | namespace |
4246 | @@ -54,7 +57,7 @@ |
4247 | EXPECT_TRUE(mir_render_surface_is_valid(rs)); |
4248 | EXPECT_THAT(mir_render_surface_get_error_message(rs), StrEq("")); |
4249 | |
4250 | - mir_render_surface_release(rs); |
4251 | + mir_render_surface_release_sync(rs); |
4252 | mir_connection_release(connection); |
4253 | } |
4254 | |
4255 | @@ -73,9 +76,13 @@ |
4256 | return {width, height}; |
4257 | }; |
4258 | auto physical_size = determine_physical_size(rs); |
4259 | - auto bs = mir_render_surface_get_buffer_stream( |
4260 | + |
4261 | + mt::Signal done; |
4262 | + |
4263 | + mir_render_surface_get_buffer_stream( |
4264 | rs, |
4265 | physical_size.width.as_int(), physical_size.height.as_int(), |
4266 | +<<<<<<< TREE |
4267 | mir_pixel_format_abgr_8888); |
4268 | |
4269 | ASSERT_THAT(bs, NotNull()); |
4270 | @@ -83,6 +90,22 @@ |
4271 | EXPECT_THAT(mir_buffer_stream_get_error_message(bs), StrEq("")); |
4272 | |
4273 | mir_render_surface_release(rs); |
4274 | +======= |
4275 | + mir_pixel_format_abgr_8888, |
4276 | + mir_buffer_usage_hardware, |
4277 | + [](MirBufferStream* bs, void* ctx) |
4278 | + { |
4279 | + ASSERT_THAT(bs, NotNull()); |
4280 | + EXPECT_THAT(bs, IsValid()); |
4281 | + |
4282 | + reinterpret_cast<mt::Signal*>(ctx)->raise(); |
4283 | + }, |
4284 | + &done); |
4285 | + |
4286 | + ASSERT_TRUE(done.wait_for(std::chrono::seconds{20})); |
4287 | + |
4288 | + mir_render_surface_release_sync(rs); |
4289 | +>>>>>>> MERGE-SOURCE |
4290 | mir_connection_release(connection); |
4291 | } |
4292 | |
4293 | @@ -94,23 +117,21 @@ |
4294 | auto rs = mir_connection_create_render_surface_sync( |
4295 | connection, logical_size.width.as_int(), logical_size.height.as_int()); |
4296 | |
4297 | - auto bs = mir_render_surface_get_buffer_stream( |
4298 | + auto bs = mir_render_surface_get_buffer_stream_sync( |
4299 | rs, |
4300 | physical_size.width.as_int(), physical_size.height.as_int(), |
4301 | mir_pixel_format_abgr_8888); |
4302 | |
4303 | - ASSERT_THAT(bs, NotNull()); |
4304 | - EXPECT_TRUE(mir_buffer_stream_is_valid(bs)); |
4305 | - EXPECT_THAT(mir_buffer_stream_get_error_message(bs), StrEq("")); |
4306 | + EXPECT_THAT(bs, IsValid()); |
4307 | |
4308 | - auto bs2 = mir_render_surface_get_buffer_stream( |
4309 | + auto bs2 = mir_render_surface_get_buffer_stream_sync( |
4310 | rs, |
4311 | physical_size.width.as_int(), physical_size.height.as_int(), |
4312 | mir_pixel_format_abgr_8888); |
4313 | |
4314 | EXPECT_THAT(bs2, Eq(nullptr)); |
4315 | |
4316 | - mir_render_surface_release(rs); |
4317 | + mir_render_surface_release_sync(rs); |
4318 | mir_connection_release(connection); |
4319 | } |
4320 | |
4321 | @@ -121,9 +142,13 @@ |
4322 | |
4323 | auto rs = mir_connection_create_render_surface_sync( |
4324 | connection, logical_size.width.as_int(), logical_size.height.as_int()); |
4325 | - auto bs = mir_render_surface_get_buffer_stream( |
4326 | + |
4327 | + mt::Signal done; |
4328 | + |
4329 | + mir_render_surface_get_buffer_stream( |
4330 | rs, |
4331 | physical_size.width.as_int(), physical_size.height.as_int(), |
4332 | +<<<<<<< TREE |
4333 | mir_pixel_format_abgr_8888); |
4334 | |
4335 | ASSERT_THAT(bs, NotNull()); |
4336 | @@ -131,6 +156,22 @@ |
4337 | EXPECT_THAT(mir_buffer_stream_get_error_message(bs), StrEq("")); |
4338 | |
4339 | mir_render_surface_release(rs); |
4340 | +======= |
4341 | + mir_pixel_format_abgr_8888, |
4342 | + mir_buffer_usage_hardware, |
4343 | + [](MirBufferStream* bs, void* ctx) |
4344 | + { |
4345 | + ASSERT_THAT(bs, NotNull()); |
4346 | + EXPECT_THAT(bs, IsValid()); |
4347 | + |
4348 | + reinterpret_cast<mt::Signal*>(ctx)->raise(); |
4349 | + }, |
4350 | + &done); |
4351 | + |
4352 | + ASSERT_TRUE(done.wait_for(std::chrono::seconds{20})); |
4353 | + |
4354 | + mir_render_surface_release_sync(rs); |
4355 | +>>>>>>> MERGE-SOURCE |
4356 | mir_connection_release(connection); |
4357 | } |
4358 | |
4359 | @@ -152,8 +193,13 @@ |
4360 | EXPECT_THAT(window, IsValid()); |
4361 | EXPECT_THAT(mir_window_get_buffer_stream(window), Eq(nullptr)); |
4362 | |
4363 | +<<<<<<< TREE |
4364 | mir_render_surface_release(rs); |
4365 | mir_window_release_sync(window); |
4366 | +======= |
4367 | + mir_render_surface_release_sync(rs); |
4368 | + mir_surface_release_sync(surface); |
4369 | +>>>>>>> MERGE-SOURCE |
4370 | mir_connection_release(connection); |
4371 | } |
4372 | |
4373 | @@ -166,19 +212,55 @@ |
4374 | |
4375 | auto rs = mir_connection_create_render_surface_sync( |
4376 | connection, logical_size.width.as_int(), logical_size.height.as_int()); |
4377 | +<<<<<<< TREE |
4378 | auto spec = mir_create_normal_window_spec(connection, width, height); |
4379 | mir_window_spec_set_pixel_format(spec, format); |
4380 | mir_window_spec_add_render_surface(spec, rs, width, height, 0, 0); |
4381 | auto window = mir_create_window_sync(spec); |
4382 | mir_window_spec_release(spec); |
4383 | auto bs = mir_render_surface_get_buffer_stream(rs, 640, 480, format); |
4384 | - |
4385 | +======= |
4386 | + auto spec = mir_connection_create_spec_for_normal_surface(connection, |
4387 | + width, height, |
4388 | + format); |
4389 | + mir_surface_spec_add_render_surface(spec, rs, width, height, 0, 0); |
4390 | + auto surface = mir_surface_create_sync(spec); |
4391 | + mir_surface_spec_release(spec); |
4392 | + mt::Signal done; |
4393 | + |
4394 | + mir_render_surface_get_buffer_stream( |
4395 | + rs, |
4396 | + 640, 480, |
4397 | + format, |
4398 | + usage, |
4399 | + [](MirBufferStream* bs, void* ctx) |
4400 | + { |
4401 | + ASSERT_THAT(bs, NotNull()); |
4402 | + EXPECT_THAT(bs, IsValid()); |
4403 | + |
4404 | + reinterpret_cast<mt::Signal*>(ctx)->raise(); |
4405 | + }, |
4406 | + &done); |
4407 | + |
4408 | +>>>>>>> MERGE-SOURCE |
4409 | + |
4410 | +<<<<<<< TREE |
4411 | EXPECT_THAT(window, IsValid()); |
4412 | EXPECT_THAT(mir_window_get_buffer_stream(window), Eq(nullptr)); |
4413 | EXPECT_TRUE(mir_buffer_stream_is_valid(bs)); |
4414 | |
4415 | mir_render_surface_release(rs); |
4416 | mir_window_release_sync(window); |
4417 | +======= |
4418 | + EXPECT_THAT(surface, IsValid()); |
4419 | + |
4420 | + EXPECT_THAT(mir_surface_get_buffer_stream(surface), Eq(nullptr)); |
4421 | + |
4422 | + ASSERT_TRUE(done.wait_for(std::chrono::seconds{20})); |
4423 | + |
4424 | + mir_render_surface_release_sync(rs); |
4425 | + mir_surface_release_sync(surface); |
4426 | +>>>>>>> MERGE-SOURCE |
4427 | mir_connection_release(connection); |
4428 | } |
4429 | |
4430 | @@ -194,7 +276,7 @@ |
4431 | ASSERT_THAT(pc, NotNull()); |
4432 | EXPECT_TRUE(mir_presentation_chain_is_valid(pc)); |
4433 | |
4434 | - mir_render_surface_release(rs); |
4435 | + mir_render_surface_release_sync(rs); |
4436 | mir_connection_release(connection); |
4437 | } |
4438 | |
4439 | @@ -214,7 +296,7 @@ |
4440 | |
4441 | EXPECT_THAT(pc2, Eq(nullptr)); |
4442 | |
4443 | - mir_render_surface_release(rs); |
4444 | + mir_render_surface_release_sync(rs); |
4445 | mir_connection_release(connection); |
4446 | } |
4447 | |
4448 | @@ -238,8 +320,13 @@ |
4449 | EXPECT_THAT(mir_window_get_buffer_stream(window), Eq(nullptr)); |
4450 | EXPECT_TRUE(mir_presentation_chain_is_valid(pc)); |
4451 | |
4452 | +<<<<<<< TREE |
4453 | mir_render_surface_release(rs); |
4454 | mir_window_release_sync(window); |
4455 | +======= |
4456 | + mir_render_surface_release_sync(rs); |
4457 | + mir_surface_release_sync(surface); |
4458 | +>>>>>>> MERGE-SOURCE |
4459 | mir_connection_release(connection); |
4460 | } |
4461 | |
4462 | @@ -254,7 +341,7 @@ |
4463 | ASSERT_THAT(pc, NotNull()); |
4464 | EXPECT_TRUE(mir_presentation_chain_is_valid(pc)); |
4465 | |
4466 | - mir_render_surface_release(rs); |
4467 | + mir_render_surface_release_sync(rs); |
4468 | mir_connection_release(connection); |
4469 | } |
4470 | |
4471 | @@ -270,14 +357,14 @@ |
4472 | ASSERT_THAT(pc, NotNull()); |
4473 | EXPECT_TRUE(mir_presentation_chain_is_valid(pc)); |
4474 | |
4475 | - auto bs = mir_render_surface_get_buffer_stream( |
4476 | + auto bs = mir_render_surface_get_buffer_stream_sync( |
4477 | rs, |
4478 | physical_size.width.as_int(), physical_size.height.as_int(), |
4479 | mir_pixel_format_abgr_8888); |
4480 | |
4481 | EXPECT_THAT(bs, Eq(nullptr)); |
4482 | |
4483 | - mir_render_surface_release(rs); |
4484 | + mir_render_surface_release_sync(rs); |
4485 | mir_connection_release(connection); |
4486 | } |
4487 | |
4488 | @@ -288,20 +375,148 @@ |
4489 | |
4490 | auto rs = mir_connection_create_render_surface_sync( |
4491 | connection, logical_size.width.as_int(), logical_size.height.as_int()); |
4492 | - auto bs = mir_render_surface_get_buffer_stream( |
4493 | + auto bs = mir_render_surface_get_buffer_stream_sync( |
4494 | rs, |
4495 | physical_size.width.as_int(), physical_size.height.as_int(), |
4496 | mir_pixel_format_abgr_8888); |
4497 | |
4498 | - ASSERT_THAT(bs, NotNull()); |
4499 | - EXPECT_TRUE(mir_buffer_stream_is_valid(bs)); |
4500 | + EXPECT_THAT(bs, IsValid()); |
4501 | |
4502 | auto pc = mir_render_surface_get_presentation_chain(rs); |
4503 | |
4504 | EXPECT_THAT(pc, Eq(nullptr)); |
4505 | |
4506 | - mir_render_surface_release(rs); |
4507 | - mir_connection_release(connection); |
4508 | + mir_render_surface_release_sync(rs); |
4509 | + mir_connection_release(connection); |
4510 | +} |
4511 | + |
4512 | +TEST_F(RenderSurfaceTest, asynchronous_render_surface_destruction_works_with_realised_buffer_stream) |
4513 | +{ |
4514 | + auto physical_size = logical_size; |
4515 | + auto connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__); |
4516 | + |
4517 | + auto rs = mir_connection_create_render_surface_sync( |
4518 | + connection, logical_size.width.as_int(), logical_size.height.as_int()); |
4519 | + mir_render_surface_get_buffer_stream_sync( |
4520 | + rs, |
4521 | + physical_size.width.as_int(), physical_size.height.as_int(), |
4522 | + mir_pixel_format_abgr_8888, |
4523 | + mir_buffer_usage_hardware); |
4524 | + |
4525 | + struct Context |
4526 | + { |
4527 | + MirRenderSurface* rs; |
4528 | + mt::Signal done; |
4529 | + } context; |
4530 | + |
4531 | + context.rs = rs; |
4532 | + |
4533 | + mir_render_surface_release( |
4534 | + rs, |
4535 | + [](MirRenderSurface* rs, void* ctx) |
4536 | + { |
4537 | + auto& context = *reinterpret_cast<Context*>(ctx); |
4538 | + EXPECT_THAT(rs, Eq(context.rs)); |
4539 | + /* |
4540 | + * Should really test that the render surface isn't valid here, but that fails. |
4541 | + * |
4542 | + EXPECT_THAT(rs, Not(IsValid())); |
4543 | + */ |
4544 | + context.done.raise(); |
4545 | + }, |
4546 | + &context); |
4547 | + |
4548 | + ASSERT_TRUE(context.done.wait_for(std::chrono::seconds{20})); |
4549 | + |
4550 | + mir_connection_release(connection); |
4551 | +} |
4552 | + |
4553 | +TEST_F(RenderSurfaceTest, asynchronous_render_surface_destruction_works_with_realised_presentation_chain) |
4554 | +{ |
4555 | + auto connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__); |
4556 | + |
4557 | + auto rs = mir_connection_create_render_surface_sync( |
4558 | + connection, logical_size.width.as_int(), logical_size.height.as_int()); |
4559 | + mir_render_surface_get_presentation_chain(rs); |
4560 | + |
4561 | + struct Context |
4562 | + { |
4563 | + MirRenderSurface* rs; |
4564 | + mt::Signal done; |
4565 | + } context; |
4566 | + |
4567 | + context.rs = rs; |
4568 | + |
4569 | + mir_render_surface_release( |
4570 | + rs, |
4571 | + [](MirRenderSurface* rs, void* ctx) |
4572 | + { |
4573 | + auto& context = *reinterpret_cast<Context*>(ctx); |
4574 | + EXPECT_THAT(rs, Eq(context.rs)); |
4575 | + /* |
4576 | + * Should really test that the render surface isn't valid here, but that fails. |
4577 | + * |
4578 | + EXPECT_THAT(rs, Not(IsValid())); |
4579 | + */ |
4580 | + context.done.raise(); |
4581 | + }, |
4582 | + &context); |
4583 | + |
4584 | + ASSERT_TRUE(context.done.wait_for(std::chrono::seconds{20})); |
4585 | + |
4586 | + mir_connection_release(connection); |
4587 | +} |
4588 | + |
4589 | +TEST_F(RenderSurfaceTest, asynchronous_render_surface_destruction_works_with_no_backing_object) |
4590 | +{ |
4591 | + auto connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__); |
4592 | + |
4593 | + auto rs = mir_connection_create_render_surface_sync( |
4594 | + connection, logical_size.width.as_int(), logical_size.height.as_int()); |
4595 | + |
4596 | + struct Context |
4597 | + { |
4598 | + MirRenderSurface* rs; |
4599 | + mt::Signal done; |
4600 | + } context; |
4601 | + |
4602 | + context.rs = rs; |
4603 | + |
4604 | + mir_render_surface_release( |
4605 | + rs, |
4606 | + [](MirRenderSurface* rs, void* ctx) |
4607 | + { |
4608 | + auto& context = *reinterpret_cast<Context*>(ctx); |
4609 | + EXPECT_THAT(rs, Eq(context.rs)); |
4610 | + /* |
4611 | + * Should really test that the render surface isn't valid here, but that fails. |
4612 | + * |
4613 | + EXPECT_THAT(rs, Not(IsValid())); |
4614 | + */ |
4615 | + context.done.raise(); |
4616 | + }, |
4617 | + &context); |
4618 | + |
4619 | + ASSERT_TRUE(context.done.wait_for(std::chrono::seconds{20})); |
4620 | + |
4621 | + mir_connection_release(connection); |
4622 | +} |
4623 | + |
4624 | +TEST_F(RenderSurfaceTest, asynchronous_destruction_calls_callback_on_failure) |
4625 | +{ |
4626 | + auto not_a_valid_client_side_rs = reinterpret_cast<MirRenderSurface*>(0x0ff01bb1); |
4627 | + |
4628 | + mt::Signal callback_called; |
4629 | + |
4630 | + mir_render_surface_release( |
4631 | + not_a_valid_client_side_rs, |
4632 | + [](MirRenderSurface*, void* ctx) |
4633 | + { |
4634 | + reinterpret_cast<mt::Signal*>(ctx)->raise(); |
4635 | + }, |
4636 | + &callback_called); |
4637 | + |
4638 | + EXPECT_TRUE(callback_called.wait_for(std::chrono::seconds{20})); |
4639 | } |
4640 | |
4641 | TEST_F(RenderSurfaceTest, stores_user_set_size_for_driver_to_access) |
4642 | |
4643 | === modified file 'tests/acceptance-tests/test_server_shutdown.cpp' |
4644 | --- tests/acceptance-tests/test_server_shutdown.cpp 2017-03-09 12:52:48 +0000 |
4645 | +++ tests/acceptance-tests/test_server_shutdown.cpp 2017-03-28 00:17:49 +0000 |
4646 | @@ -25,7 +25,7 @@ |
4647 | #include "mir_test_framework/executable_path.h" |
4648 | #include "mir/test/doubles/null_logger.h" |
4649 | |
4650 | -#include <gtest/gtest.h> |
4651 | +#include </usr/include/gtest/gtest.h> |
4652 | |
4653 | namespace mt = mir::test; |
4654 | namespace mtf = mir_test_framework; |
4655 | |
4656 | === added file 'tests/include/mir/test/doubles/mock_client_buffer_stream_factory.h.THIS' |
4657 | --- tests/include/mir/test/doubles/mock_client_buffer_stream_factory.h.THIS 1970-01-01 00:00:00 +0000 |
4658 | +++ tests/include/mir/test/doubles/mock_client_buffer_stream_factory.h.THIS 2017-03-28 00:17:49 +0000 |
4659 | @@ -0,0 +1,59 @@ |
4660 | +/* |
4661 | + * Copyright © 2015 Canonical Ltd. |
4662 | + * |
4663 | + * This program is free software: you can redistribute it and/or modify it |
4664 | + * under the terms of the GNU General Public License version 3, |
4665 | + * as published by the Free Software Foundation. |
4666 | + * |
4667 | + * This program is distributed in the hope that it will be useful, |
4668 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
4669 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
4670 | + * GNU General Public License for more details. |
4671 | + * |
4672 | + * You should have received a copy of the GNU General Public License |
4673 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
4674 | + * |
4675 | + * Authored by: Robert Carr <robert.carr@canonical.com> |
4676 | + */ |
4677 | + |
4678 | +#ifndef MIR_TEST_DOUBLES_MOCK_CLIENT_BUFFER_STREAM_FACTORY_H_ |
4679 | +#define MIR_TEST_DOUBLES_MOCK_CLIENT_BUFFER_STREAM_FACTORY_H_ |
4680 | + |
4681 | +#include "src/client/client_buffer_stream_factory.h" |
4682 | +#include "src/client/buffer_stream.h" |
4683 | + |
4684 | +#include <gtest/gtest.h> |
4685 | +#include <gmock/gmock.h> |
4686 | + |
4687 | +namespace mir |
4688 | +{ |
4689 | +namespace test |
4690 | +{ |
4691 | +namespace doubles |
4692 | +{ |
4693 | + |
4694 | +struct MockClientBufferStreamFactory : public client::ClientBufferStreamFactory |
4695 | +{ |
4696 | + MOCK_METHOD4(make_consumer_stream, std::shared_ptr<client::ClientBufferStream>( |
4697 | + MirConnection*, |
4698 | + protobuf::DisplayServer&, |
4699 | + protobuf::BufferStream const&, |
4700 | + std::string const&)); |
4701 | + MOCK_METHOD4(make_producer_stream, std::shared_ptr<client::ClientBufferStream>( |
4702 | + MirConnection*, |
4703 | + protobuf::DisplayServer&, |
4704 | + protobuf::BufferStream const&, |
4705 | + std::string const&)); |
4706 | + MOCK_METHOD5(make_producer_stream, client::ClientBufferStream*( |
4707 | + MirConnection*, |
4708 | + protobuf::DisplayServer&, |
4709 | + protobuf::BufferStreamParameters const&, |
4710 | + mir_buffer_stream_callback callback, |
4711 | + void* context)); |
4712 | +}; |
4713 | + |
4714 | +} |
4715 | +} |
4716 | +} |
4717 | + |
4718 | +#endif // MIR_TEST_DOUBLES_MOCK_CLIENT_BUFFER_STREAM_FACTORY_H_ |
4719 | |
4720 | === modified file 'tests/include/mir/test/doubles/mock_mir_buffer_stream.h' |
4721 | --- tests/include/mir/test/doubles/mock_mir_buffer_stream.h 2017-03-10 19:47:57 +0000 |
4722 | +++ tests/include/mir/test/doubles/mock_mir_buffer_stream.h 2017-03-28 00:17:49 +0000 |
4723 | @@ -50,6 +50,7 @@ |
4724 | MOCK_METHOD0(get_create_wait_handle, MirWaitHandle*(void)); |
4725 | MOCK_CONST_METHOD0(rpc_id, frontend::BufferStreamId(void)); |
4726 | MOCK_CONST_METHOD0(valid, bool(void)); |
4727 | + MOCK_CONST_METHOD0(has_buffer, bool(void)); |
4728 | MOCK_METHOD1(buffer_available, void(mir::protobuf::Buffer const&)); |
4729 | MOCK_METHOD0(buffer_unavailable, void()); |
4730 | MOCK_METHOD1(set_size, void(geometry::Size)); |
4731 | |
4732 | === modified file 'tests/include/mir/test/doubles/stub_buffer_stream_factory.h' |
4733 | --- tests/include/mir/test/doubles/stub_buffer_stream_factory.h 2017-03-13 08:12:52 +0000 |
4734 | +++ tests/include/mir/test/doubles/stub_buffer_stream_factory.h 2017-03-28 00:17:49 +0000 |
4735 | @@ -21,7 +21,10 @@ |
4736 | |
4737 | #include "mir/frontend/client_buffers.h" |
4738 | #include "mir/scene/buffer_stream_factory.h" |
4739 | +#include "mir/frontend/buffer_sink.h" |
4740 | #include "stub_buffer_stream.h" |
4741 | +#include "stub_buffer.h" |
4742 | +#include "mir_test_framework/stub_platform_native_buffer.h" |
4743 | |
4744 | namespace mir |
4745 | { |
4746 | @@ -32,8 +35,20 @@ |
4747 | |
4748 | struct StubClientBuffers : frontend::ClientBuffers |
4749 | { |
4750 | +<<<<<<< TREE |
4751 | graphics::BufferID add_buffer(std::shared_ptr<graphics::Buffer> const&) override |
4752 | { |
4753 | +======= |
4754 | + StubClientBuffers(std::shared_ptr<frontend::BufferSink> const& sink) |
4755 | + : sink{sink} |
4756 | + { |
4757 | + } |
4758 | + |
4759 | + graphics::BufferID add_buffer(graphics::BufferProperties const& props) override |
4760 | + { |
4761 | + StubBuffer buf{std::make_shared<mir_test_framework::NativeBuffer>(props), props.size}; |
4762 | + sink->add_buffer(buf); |
4763 | +>>>>>>> MERGE-SOURCE |
4764 | return {}; |
4765 | } |
4766 | void remove_buffer(graphics::BufferID) override |
4767 | @@ -50,6 +65,7 @@ |
4768 | { |
4769 | } |
4770 | std::shared_ptr<graphics::Buffer> buffer; |
4771 | + std::shared_ptr<frontend::BufferSink> const sink; |
4772 | }; |
4773 | |
4774 | struct StubBufferStreamFactory : public scene::BufferStreamFactory |
4775 | @@ -61,9 +77,9 @@ |
4776 | frontend::BufferStreamId, std::shared_ptr<frontend::ClientBuffers> const&, |
4777 | graphics::BufferProperties const&) { return std::make_shared<StubBufferStream>(); } |
4778 | std::shared_ptr<frontend::ClientBuffers> create_buffer_map( |
4779 | - std::shared_ptr<frontend::BufferSink> const&) |
4780 | + std::shared_ptr<frontend::BufferSink> const& sink) |
4781 | { |
4782 | - return std::make_shared<StubClientBuffers>(); |
4783 | + return std::make_shared<StubClientBuffers>(sink); |
4784 | } |
4785 | }; |
4786 | } |
4787 | |
4788 | === added file 'tests/include/mir/test/doubles/stub_client_buffer_stream_factory.h.THIS' |
4789 | --- tests/include/mir/test/doubles/stub_client_buffer_stream_factory.h.THIS 1970-01-01 00:00:00 +0000 |
4790 | +++ tests/include/mir/test/doubles/stub_client_buffer_stream_factory.h.THIS 2017-03-28 00:17:49 +0000 |
4791 | @@ -0,0 +1,66 @@ |
4792 | +/* |
4793 | + * Copyright © 2015 Canonical Ltd. |
4794 | + * |
4795 | + * This program is free software: you can redistribute it and/or modify it |
4796 | + * under the terms of the GNU General Public License version 3, |
4797 | + * as published by the Free Software Foundation. |
4798 | + * |
4799 | + * This program is distributed in the hope that it will be useful, |
4800 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
4801 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
4802 | + * GNU General Public License for more details. |
4803 | + * |
4804 | + * You should have received a copy of the GNU General Public License |
4805 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
4806 | + * |
4807 | + * Authored by: Robert Carr <robert.carr@canonical.com> |
4808 | + */ |
4809 | + |
4810 | +#ifndef MIR_TEST_DOUBLES_STUB_CLIENT_BUFFER_STREAM_FACTORY_H_ |
4811 | +#define MIR_TEST_DOUBLES_STUB_CLIENT_BUFFER_STREAM_FACTORY_H_ |
4812 | + |
4813 | +#include "src/client/client_buffer_stream_factory.h" |
4814 | +#include "src/client/buffer_stream.h" |
4815 | + |
4816 | +namespace mir |
4817 | +{ |
4818 | +namespace test |
4819 | +{ |
4820 | +namespace doubles |
4821 | +{ |
4822 | + |
4823 | +struct StubClientBufferStreamFactory : public client::ClientBufferStreamFactory |
4824 | +{ |
4825 | + std::shared_ptr<client::ClientBufferStream> make_consumer_stream( |
4826 | + MirConnection* /* allocating_connection */, |
4827 | + protobuf::DisplayServer& /* server */, |
4828 | + protobuf::BufferStream const& /* protobuf_bs */, |
4829 | + std::string const& /* surface_name */) override |
4830 | + { |
4831 | + return nullptr; |
4832 | + } |
4833 | + |
4834 | + std::shared_ptr<client::ClientBufferStream> make_producer_stream( |
4835 | + MirConnection* /* allocating_connection */, |
4836 | + protobuf::DisplayServer& /* server */, |
4837 | + protobuf::BufferStream const& /* protobuf_bs */, |
4838 | + std::string const& /* surface_name */) override |
4839 | + { |
4840 | + return nullptr; |
4841 | + } |
4842 | + |
4843 | + client::ClientBufferStream* make_producer_stream( |
4844 | + MirConnection* /* allocating_connection */, |
4845 | + protobuf::DisplayServer& /* server */, |
4846 | + protobuf::BufferStreamParameters const& /* params */, |
4847 | + mir_buffer_stream_callback /* callback */, void* /* context */) override |
4848 | + { |
4849 | + return nullptr; |
4850 | + } |
4851 | +}; |
4852 | + |
4853 | +} |
4854 | +} |
4855 | +} |
4856 | + |
4857 | +#endif // MIR_TEST_DOUBLES_STUB_CLIENT_BUFFER_STREAM_FACTORY_H_ |
4858 | |
4859 | === modified file 'tests/integration-tests/test_buffer_scheduling.cpp' |
4860 | --- tests/integration-tests/test_buffer_scheduling.cpp 2017-03-13 08:12:52 +0000 |
4861 | +++ tests/integration-tests/test_buffer_scheduling.cpp 2017-03-28 00:17:49 +0000 |
4862 | @@ -27,6 +27,7 @@ |
4863 | #include "src/client/connection_surface_map.h" |
4864 | #include "src/server/compositor/stream.h" |
4865 | #include "src/server/compositor/buffer_map.h" |
4866 | +#include "mir/dispatch/action_queue.h" |
4867 | #include "mir/test/doubles/stub_client_buffer_factory.h" |
4868 | #include "mir/test/doubles/mock_client_buffer_factory.h" |
4869 | #include "mir/test/doubles/stub_buffer_allocator.h" |
4870 | @@ -37,6 +38,7 @@ |
4871 | |
4872 | namespace mt = mir::test; |
4873 | namespace mtd = mir::test::doubles; |
4874 | +namespace md = mir::dispatch; |
4875 | namespace mcl = mir::client; |
4876 | namespace mc = mir::compositor; |
4877 | namespace mg = mir::graphics; |
4878 | @@ -290,7 +292,7 @@ |
4879 | { |
4880 | ScheduledProducer(std::shared_ptr<StubIpcSystem> const& ipc_stub, int nbuffers) : |
4881 | ipc(ipc_stub), |
4882 | - map(std::make_shared<mcl::ConnectionSurfaceMap>()), |
4883 | + map(std::make_shared<mcl::ConnectionSurfaceMap>(std::make_shared<md::ActionQueue>())), |
4884 | factory(std::make_shared<mcl::BufferFactory>()), |
4885 | vault( |
4886 | std::make_shared<mtd::StubClientBufferFactory>(), factory, |
4887 | |
4888 | === modified file 'tests/integration-tests/test_surfaceloop.cpp' |
4889 | --- tests/integration-tests/test_surfaceloop.cpp 2017-01-18 02:29:37 +0000 |
4890 | +++ tests/integration-tests/test_surfaceloop.cpp 2017-03-28 00:17:49 +0000 |
4891 | @@ -17,6 +17,7 @@ |
4892 | */ |
4893 | |
4894 | #include "mir_toolkit/mir_client_library.h" |
4895 | +#include "mir/graphics/buffer_ipc_message.h" |
4896 | |
4897 | #include "mir/test/doubles/stub_buffer.h" |
4898 | #include "mir/test/doubles/stub_buffer_allocator.h" |
4899 | @@ -33,6 +34,7 @@ |
4900 | #include <condition_variable> |
4901 | #include <gmock/gmock.h> |
4902 | #include <gtest/gtest.h> |
4903 | +#include <src/client/lttng/shared_library_prober_report_tp.h> |
4904 | #include "mir/test/gmock_fixes.h" |
4905 | |
4906 | namespace mc = mir::compositor; |
4907 | @@ -44,35 +46,6 @@ |
4908 | |
4909 | namespace |
4910 | { |
4911 | -geom::Size const size{640, 480}; |
4912 | -MirPixelFormat const format{mir_pixel_format_abgr_8888}; |
4913 | -mg::BufferUsage const usage{mg::BufferUsage::hardware}; |
4914 | -mg::BufferProperties const buffer_properties{size, format, usage}; |
4915 | - |
4916 | - |
4917 | -class MockGraphicBufferAllocator : public mtd::StubBufferAllocator |
4918 | -{ |
4919 | - public: |
4920 | - MockGraphicBufferAllocator() |
4921 | - { |
4922 | - using testing::_; |
4923 | - ON_CALL(*this, alloc_buffer(_)) |
4924 | - .WillByDefault(testing::Invoke(this, &MockGraphicBufferAllocator::on_create_swapper)); |
4925 | - } |
4926 | - |
4927 | - MOCK_METHOD1( |
4928 | - alloc_buffer, |
4929 | - std::shared_ptr<mg::Buffer> (mg::BufferProperties const&)); |
4930 | - |
4931 | - |
4932 | - std::shared_ptr<mg::Buffer> on_create_swapper(mg::BufferProperties const&) |
4933 | - { |
4934 | - return std::make_shared<mtd::StubBuffer>(::buffer_properties); |
4935 | - } |
4936 | - |
4937 | - ~MockGraphicBufferAllocator() noexcept {} |
4938 | -}; |
4939 | - |
4940 | class StubDisplay : public mtd::NullDisplay |
4941 | { |
4942 | public: |
4943 | @@ -96,11 +69,13 @@ |
4944 | { |
4945 | public: |
4946 | |
4947 | - CountingStubBuffer() |
4948 | + CountingStubBuffer(mg::BufferProperties const& props) |
4949 | + : StubBuffer(props) |
4950 | { |
4951 | std::lock_guard<std::mutex> lock{buffers_mutex}; |
4952 | ++buffers_created; |
4953 | buffers_cv.notify_one(); |
4954 | + std::cout << "Created buffer with size " << size() << std::endl; |
4955 | } |
4956 | ~CountingStubBuffer() |
4957 | { |
4958 | @@ -118,11 +93,61 @@ |
4959 | class StubGraphicBufferAllocator : public mtd::StubBufferAllocator |
4960 | { |
4961 | public: |
4962 | - std::shared_ptr<mg::Buffer> alloc_buffer(mg::BufferProperties const&) override |
4963 | - { |
4964 | - return std::make_shared<CountingStubBuffer>(); |
4965 | - } |
4966 | - }; |
4967 | + std::shared_ptr<mg::Buffer> alloc_buffer(mg::BufferProperties const& props) override |
4968 | + { |
4969 | + return std::make_shared<CountingStubBuffer>(props); |
4970 | + } |
4971 | + }; |
4972 | +<<<<<<< TREE |
4973 | +======= |
4974 | + |
4975 | + class StubPlatform : public mtd::NullPlatform |
4976 | + { |
4977 | + public: |
4978 | + mir::UniqueModulePtr<mg::GraphicBufferAllocator> create_buffer_allocator() override |
4979 | + { |
4980 | + return mir::make_module_ptr<StubGraphicBufferAllocator>(); |
4981 | + } |
4982 | + |
4983 | + mir::UniqueModulePtr<mg::Display> create_display( |
4984 | + std::shared_ptr<mg::DisplayConfigurationPolicy> const&, |
4985 | + std::shared_ptr<mg::GLConfig> const&) override |
4986 | + { |
4987 | + return mir::make_module_ptr<StubDisplay>(); |
4988 | + } |
4989 | + |
4990 | + mir::UniqueModulePtr<mg::PlatformIpcOperations> make_ipc_operations() const override |
4991 | + { |
4992 | + class BufferPackingIPCOperations : public mtd::NullPlatformIpcOperations |
4993 | + { |
4994 | + public: |
4995 | + void pack_buffer( |
4996 | + mg::BufferIpcMessage& message, |
4997 | + mg::Buffer const& buffer, |
4998 | + mg::BufferIpcMsgType msg_type) const override |
4999 | + { |
5000 | + if (msg_type == mg::BufferIpcMsgType::full_msg) |
FAILED: Continuous integration, rev:2326 jenkins. qa.ubuntu. com/job/ mir-ci/ 2841/ jenkins. qa.ubuntu. com/job/ mir-android- vivid-i386- build/1105 jenkins. qa.ubuntu. com/job/ mir-clang- vivid-amd64- build/1104 jenkins. qa.ubuntu. com/job/ mir-mediumtests -vivid- touch/1066/ console jenkins. qa.ubuntu. com/job/ mir-vivid- amd64-ci/ 838/console jenkins. qa.ubuntu. com/job/ mir-mediumtests -builder- vivid-armhf/ 1066 jenkins. qa.ubuntu. com/job/ mir-mediumtests -builder- vivid-armhf/ 1066/artifact/ work/output/ *zip*/output. zip jenkins. qa.ubuntu. com/job/ mir-mediumtests -runner- mako/4122/ console s-jenkins. ubuntu- ci:8080/ job/touch- flash-device/ 17541
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
FAILURE: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/mir- ci/2841/ rebuild
http://