Mir

Merge lp:~kdub/mir/fix-1664562 into lp:mir

Proposed by Kevin DuBois
Status: Merged
Approved by: Daniel van Vugt
Approved revision: no longer in the source branch.
Merged at revision: 4040
Proposed branch: lp:~kdub/mir/fix-1664562
Merge into: lp:mir
Diff against target: 900 lines (+535/-230)
10 files modified
src/server/graphics/nested/CMakeLists.txt (+1/-0)
src/server/graphics/nested/host_buffer.cpp (+183/-0)
src/server/graphics/nested/host_buffer.h (+73/-0)
src/server/graphics/nested/mir_client_host_connection.cpp (+5/-174)
tests/include/mir/test/doubles/mock_client_platform.h (+76/-0)
tests/include/mir/test/doubles/stub_client_platform_factory.h (+50/-0)
tests/include/mir/test/stub_server_tool.h (+14/-0)
tests/unit-tests/client/test_mir_render_surface.cpp (+5/-56)
tests/unit-tests/platforms/nested/CMakeLists.txt (+1/-0)
tests/unit-tests/platforms/nested/test_host_buffer.cpp (+127/-0)
To merge this branch: bzr merge lp:~kdub/mir/fix-1664562
Reviewer Review Type Date Requested Status
Daniel van Vugt Abstain
Chris Halse Rogers Approve
Mir CI Bot continuous-integration Approve
Review via email: mp+317235@code.launchpad.net

Commit message

nested: make sure not to close the FD given via the fenced_buffers extension. This was causing intermittent problems with mirscreencast on fenced platforms (android)

fixes: LP: #1664562

Description of the change

nested: make sure not to close the FD given via the fenced_buffers extension. This was causing intermittent problems with mirscreencast on fenced platforms (android)

fixes: LP: #1664562

one line of change... line 448 changed to line 194. The rest was extruding classes to their own files to come up with the test.

To post a comment you must log in.
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

PASSED: Continuous integration, rev:4029
https://mir-jenkins.ubuntu.com/job/mir-ci/2995/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-mir/3990
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/4076
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/4066
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial+overlay/4066
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/4066
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4017
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4017/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/4017
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/4017/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4017
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4017/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/4017
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/4017/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/4017
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/4017/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/4017
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/4017/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/2995/rebuild

review: Approve (continuous-integration)
Revision history for this message
Chris Halse Rogers (raof) wrote :

I'd kinda prefer this to be just the one-line change, rather than all the changes to make a test :).

That said, looks fine to me.

review: Approve
Revision history for this message
Daniel van Vugt (vanvugt) wrote :

I agree with Chris, although it's also fine putting a larger cleanup on trunk. Only if you were backporting the fix to a stable branch like lp:mir/0.26 then you should choose the one-liner solution over this.

review: Abstain

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/server/graphics/nested/CMakeLists.txt'
2--- src/server/graphics/nested/CMakeLists.txt 2017-01-18 02:29:37 +0000
3+++ src/server/graphics/nested/CMakeLists.txt 2017-02-14 17:05:00 +0000
4@@ -15,4 +15,5 @@
5 platform.cpp
6 buffer.cpp
7 ipc_operations.cpp
8+ host_buffer.cpp
9 )
10
11=== added file 'src/server/graphics/nested/host_buffer.cpp'
12--- src/server/graphics/nested/host_buffer.cpp 1970-01-01 00:00:00 +0000
13+++ src/server/graphics/nested/host_buffer.cpp 2017-02-14 17:05:00 +0000
14@@ -0,0 +1,183 @@
15+/*
16+ * Copyright © 2017 Canonical Ltd.
17+ *
18+ * This program is free software: you can redistribute it and/or modify it
19+ * under the terms of the GNU General Public License version 3,
20+ * as published by the Free Software Foundation.
21+ *
22+ * This program is distributed in the hope that it will be useful,
23+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
24+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25+ * GNU General Public License for more details.
26+ *
27+ * You should have received a copy of the GNU General Public License
28+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
29+ *
30+ * Authored by: Kevin DuBois <kevin.dubois@canonical.com>
31+ */
32+
33+#include "host_buffer.h"
34+#include "mir_toolkit/mir_buffer_private.h"
35+#include <boost/throw_exception.hpp>
36+
37+namespace mg = mir::graphics;
38+namespace mgn = mir::graphics::nested;
39+namespace geom = mir::geometry;
40+
41+mgn::HostBuffer::HostBuffer(MirConnection* mir_connection, mg::BufferProperties const& properties) :
42+ fence_extensions(mir_extension_fenced_buffers_v1(mir_connection))
43+{
44+ mir_connection_allocate_buffer(
45+ mir_connection,
46+ properties.size.width.as_int(),
47+ properties.size.height.as_int(),
48+ properties.format,
49+ buffer_available, this);
50+ std::unique_lock<std::mutex> lk(mut);
51+ cv.wait(lk, [&]{ return handle; });
52+ if (!mir_buffer_is_valid(handle))
53+ {
54+ mir_buffer_release(handle);
55+ BOOST_THROW_EXCEPTION(std::runtime_error("could not allocate MirBuffer"));
56+ }
57+}
58+
59+mgn::HostBuffer::HostBuffer(MirConnection* mir_connection, geom::Size size, MirPixelFormat format) :
60+ fence_extensions(mir_extension_fenced_buffers_v1(mir_connection))
61+{
62+ mir_connection_allocate_buffer(
63+ mir_connection,
64+ size.width.as_int(),
65+ size.height.as_int(),
66+ format,
67+ buffer_available, this);
68+ std::unique_lock<std::mutex> lk(mut);
69+ cv.wait(lk, [&]{ return handle; });
70+ if (!mir_buffer_is_valid(handle))
71+ {
72+ mir_buffer_release(handle);
73+ BOOST_THROW_EXCEPTION(std::runtime_error("could not allocate MirBuffer"));
74+ }
75+}
76+
77+mgn::HostBuffer::HostBuffer(MirConnection* mir_connection,
78+ MirExtensionGbmBufferV1 const* ext,
79+ geom::Size size, unsigned int native_pf, unsigned int native_flags) :
80+ fence_extensions(mir_extension_fenced_buffers_v1(mir_connection))
81+{
82+ ext->allocate_buffer_gbm(
83+ mir_connection, size.width.as_int(), size.height.as_int(), native_pf, native_flags,
84+ buffer_available, this);
85+ std::unique_lock<std::mutex> lk(mut);
86+ cv.wait(lk, [&]{ return handle; });
87+ if (!mir_buffer_is_valid(handle))
88+ {
89+ mir_buffer_release(handle);
90+ BOOST_THROW_EXCEPTION(std::runtime_error("could not allocate MirBuffer"));
91+ }
92+}
93+
94+mgn::HostBuffer::HostBuffer(MirConnection* mir_connection,
95+ MirExtensionAndroidBufferV1 const* ext,
96+ geom::Size size, unsigned int native_pf, unsigned int native_flags) :
97+ fence_extensions(mir_extension_fenced_buffers_v1(mir_connection))
98+{
99+ ext->allocate_buffer_android(
100+ mir_connection, size.width.as_int(), size.height.as_int(), native_pf, native_flags,
101+ buffer_available, this);
102+ std::unique_lock<std::mutex> lk(mut);
103+ cv.wait(lk, [&]{ return handle; });
104+ if (!mir_buffer_is_valid(handle))
105+ {
106+ mir_buffer_release(handle);
107+ BOOST_THROW_EXCEPTION(std::runtime_error("could not allocate MirBuffer"));
108+ }
109+}
110+
111+mgn::HostBuffer::~HostBuffer()
112+{
113+ mir_buffer_release(handle);
114+}
115+
116+void mgn::HostBuffer::sync(MirBufferAccess access, std::chrono::nanoseconds ns)
117+{
118+ if (fence_extensions && fence_extensions->wait_for_access)
119+ fence_extensions->wait_for_access(handle, access, ns.count());
120+}
121+
122+MirBuffer* mgn::HostBuffer::client_handle() const
123+{
124+ return handle;
125+}
126+
127+std::unique_ptr<mgn::GraphicsRegion> mgn::HostBuffer::get_graphics_region()
128+{
129+ return std::make_unique<mgn::GraphicsRegion>(handle);
130+}
131+
132+geom::Size mgn::HostBuffer::size() const
133+{
134+ return { mir_buffer_get_width(handle), mir_buffer_get_height(handle) };
135+}
136+
137+MirPixelFormat mgn::HostBuffer::format() const
138+{
139+ return mir_buffer_get_pixel_format(handle);
140+}
141+
142+std::tuple<EGLenum, EGLClientBuffer, EGLint*> mgn::HostBuffer::egl_image_creation_hints() const
143+{
144+ EGLenum type;
145+ EGLClientBuffer client_buffer = nullptr;;
146+ EGLint* attrs = nullptr;
147+ // TODO: check return value
148+ mir_buffer_get_egl_image_parameters(handle, &type, &client_buffer, &attrs);
149+
150+ return std::tuple<EGLenum, EGLClientBuffer, EGLint*>{type, client_buffer, attrs};
151+}
152+
153+void mgn::HostBuffer::buffer_available(MirBuffer* buffer, void* context)
154+{
155+ auto host_buffer = static_cast<HostBuffer*>(context);
156+ host_buffer->available(buffer);
157+}
158+
159+void mgn::HostBuffer::available(MirBuffer* buffer)
160+{
161+ std::unique_lock<std::mutex> lk(mut);
162+ if (!handle)
163+ {
164+ handle = buffer;
165+ cv.notify_all();
166+ }
167+
168+ auto g = f;
169+ lk.unlock();
170+ if (g)
171+ g();
172+}
173+
174+void mgn::HostBuffer::on_ownership_notification(std::function<void()> const& fn)
175+{
176+ std::unique_lock<std::mutex> lk(mut);
177+ f = fn;
178+}
179+
180+MirBufferPackage* mgn::HostBuffer::package() const
181+{
182+ return mir_buffer_get_buffer_package(handle);
183+}
184+
185+void mgn::HostBuffer::set_fence(mir::Fd fd)
186+{
187+ if (fence_extensions && fence_extensions->associate_fence)
188+ fence_extensions->associate_fence(handle, fd, mir_read_write);
189+}
190+
191+mir::Fd mgn::HostBuffer::fence() const
192+{
193+ if (fence_extensions && fence_extensions->get_fence)
194+ return mir::Fd{mir::IntOwnedFd{fence_extensions->get_fence(handle)}};
195+ else
196+ return mir::Fd{mir::Fd::invalid};
197+}
198
199=== added file 'src/server/graphics/nested/host_buffer.h'
200--- src/server/graphics/nested/host_buffer.h 1970-01-01 00:00:00 +0000
201+++ src/server/graphics/nested/host_buffer.h 2017-02-14 17:05:00 +0000
202@@ -0,0 +1,73 @@
203+/*
204+ * Copyright © 2017 Canonical Ltd.
205+ *
206+ * This program is free software: you can redistribute it and/or modify it
207+ * under the terms of the GNU General Public License version 3,
208+ * as published by the Free Software Foundation.
209+ *
210+ * This program is distributed in the hope that it will be useful,
211+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
212+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
213+ * GNU General Public License for more details.
214+ *
215+ * You should have received a copy of the GNU General Public License
216+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
217+ *
218+ * Authored by: Kevin DuBois <kevin.dubois@canonical.com>
219+ */
220+
221+#ifndef MIR_GRAPHICS_NESTED_HOST_BUFFER_H_
222+#define MIR_GRAPHICS_NESTED_HOST_BUFFER_H_
223+
224+#include "mir/graphics/buffer_properties.h"
225+#include "mir_toolkit/mir_buffer.h"
226+#include "mir_toolkit/extensions/gbm_buffer.h"
227+#include "mir_toolkit/extensions/android_buffer.h"
228+#include "native_buffer.h"
229+#include <functional>
230+#include <mutex>
231+#include <condition_variable>
232+
233+namespace mir
234+{
235+namespace graphics
236+{
237+namespace nested
238+{
239+class HostBuffer : public NativeBuffer
240+{
241+public:
242+ HostBuffer(MirConnection* mir_connection, BufferProperties const& properties);
243+ HostBuffer(MirConnection* mir_connection, geometry::Size size, MirPixelFormat format);
244+ HostBuffer(MirConnection* mir_connection,
245+ MirExtensionGbmBufferV1 const* ext,
246+ geometry::Size size, unsigned int native_pf, unsigned int native_flags);
247+ HostBuffer(MirConnection* mir_connection,
248+ MirExtensionAndroidBufferV1 const* ext,
249+ geometry::Size size, unsigned int native_pf, unsigned int native_flags);
250+ ~HostBuffer();
251+
252+ void sync(MirBufferAccess access, std::chrono::nanoseconds ns) override;
253+ MirBuffer* client_handle() const override;
254+ std::unique_ptr<GraphicsRegion> get_graphics_region() override;
255+ geometry::Size size() const override;
256+ MirPixelFormat format() const override;
257+ std::tuple<EGLenum, EGLClientBuffer, EGLint*> egl_image_creation_hints() const override;
258+ static void buffer_available(MirBuffer* buffer, void* context);
259+ void available(MirBuffer* buffer) override;
260+ void on_ownership_notification(std::function<void()> const& fn) override;
261+ MirBufferPackage* package() const override;
262+ void set_fence(mir::Fd fd) override;
263+ mir::Fd fence() const override;
264+
265+private:
266+ MirExtensionFencedBuffersV1 const* fence_extensions = nullptr;
267+ std::function<void()> f;
268+ MirBuffer* handle = nullptr;
269+ std::mutex mut;
270+ std::condition_variable cv;
271+};
272+}
273+}
274+}
275+#endif /* MIR_GRAPHICS_NESTED_HOST_BUFFER_H_ */
276
277=== modified file 'src/server/graphics/nested/mir_client_host_connection.cpp'
278--- src/server/graphics/nested/mir_client_host_connection.cpp 2017-02-14 07:05:13 +0000
279+++ src/server/graphics/nested/mir_client_host_connection.cpp 2017-02-14 17:05:00 +0000
280@@ -21,6 +21,7 @@
281 #include "host_stream.h"
282 #include "host_chain.h"
283 #include "host_surface_spec.h"
284+#include "host_buffer.h"
285 #include "native_buffer.h"
286 #include "mir_toolkit/mir_client_library.h"
287 #include "mir_toolkit/mir_extension_core.h"
288@@ -610,176 +611,6 @@
289
290 namespace
291 {
292-class HostBuffer : public mgn::NativeBuffer
293-{
294-public:
295- HostBuffer(MirConnection* mir_connection, mg::BufferProperties const& properties) :
296- fence_extensions(mir_extension_fenced_buffers_v1(mir_connection))
297- {
298- mir_connection_allocate_buffer(
299- mir_connection,
300- properties.size.width.as_int(),
301- properties.size.height.as_int(),
302- properties.format,
303- buffer_available, this);
304- std::unique_lock<std::mutex> lk(mut);
305- cv.wait(lk, [&]{ return handle; });
306- if (!mir_buffer_is_valid(handle))
307- {
308- mir_buffer_release(handle);
309- BOOST_THROW_EXCEPTION(std::runtime_error("could not allocate MirBuffer"));
310- }
311- }
312-
313- HostBuffer(MirConnection* mir_connection, geom::Size size, MirPixelFormat format) :
314- fence_extensions(mir_extension_fenced_buffers_v1(mir_connection))
315- {
316- mir_connection_allocate_buffer(
317- mir_connection,
318- size.width.as_int(),
319- size.height.as_int(),
320- format,
321- buffer_available, this);
322- std::unique_lock<std::mutex> lk(mut);
323- cv.wait(lk, [&]{ return handle; });
324- if (!mir_buffer_is_valid(handle))
325- {
326- mir_buffer_release(handle);
327- BOOST_THROW_EXCEPTION(std::runtime_error("could not allocate MirBuffer"));
328- }
329- }
330-
331- HostBuffer(MirConnection* mir_connection,
332- MirExtensionGbmBufferV1 const* ext,
333- geom::Size size, unsigned int native_pf, unsigned int native_flags) :
334- fence_extensions(mir_extension_fenced_buffers_v1(mir_connection))
335- {
336- ext->allocate_buffer_gbm(
337- mir_connection, size.width.as_int(), size.height.as_int(), native_pf, native_flags,
338- buffer_available, this);
339- std::unique_lock<std::mutex> lk(mut);
340- cv.wait(lk, [&]{ return handle; });
341- if (!mir_buffer_is_valid(handle))
342- {
343- mir_buffer_release(handle);
344- BOOST_THROW_EXCEPTION(std::runtime_error("could not allocate MirBuffer"));
345- }
346- }
347-
348- HostBuffer(MirConnection* mir_connection,
349- MirExtensionAndroidBufferV1 const* ext,
350- geom::Size size, unsigned int native_pf, unsigned int native_flags) :
351- fence_extensions(mir_extension_fenced_buffers_v1(mir_connection))
352- {
353- ext->allocate_buffer_android(
354- mir_connection, size.width.as_int(), size.height.as_int(), native_pf, native_flags,
355- buffer_available, this);
356- std::unique_lock<std::mutex> lk(mut);
357- cv.wait(lk, [&]{ return handle; });
358- if (!mir_buffer_is_valid(handle))
359- {
360- mir_buffer_release(handle);
361- BOOST_THROW_EXCEPTION(std::runtime_error("could not allocate MirBuffer"));
362- }
363- }
364-
365- ~HostBuffer()
366- {
367- mir_buffer_release(handle);
368- }
369-
370- void sync(MirBufferAccess access, std::chrono::nanoseconds ns) override
371- {
372- if (fence_extensions && fence_extensions->wait_for_access)
373- fence_extensions->wait_for_access(handle, access, ns.count());
374- }
375-
376- MirBuffer* client_handle() const override
377- {
378- return handle;
379- }
380-
381- std::unique_ptr<mgn::GraphicsRegion> get_graphics_region() override
382- {
383- return std::make_unique<mgn::GraphicsRegion>(handle);
384- }
385-
386- geom::Size size() const override
387- {
388- return { mir_buffer_get_width(handle), mir_buffer_get_height(handle) };
389- }
390-
391- MirPixelFormat format() const override
392- {
393- return mir_buffer_get_pixel_format(handle);
394- }
395-
396- std::tuple<EGLenum, EGLClientBuffer, EGLint*> egl_image_creation_hints() const override
397- {
398- EGLenum type;
399- EGLClientBuffer client_buffer = nullptr;;
400- EGLint* attrs = nullptr;
401- // TODO: check return value
402- mir_buffer_get_egl_image_parameters(handle, &type, &client_buffer, &attrs);
403-
404- return std::tuple<EGLenum, EGLClientBuffer, EGLint*>{type, client_buffer, attrs};
405- }
406-
407- static void buffer_available(MirBuffer* buffer, void* context)
408- {
409- auto host_buffer = static_cast<HostBuffer*>(context);
410- host_buffer->available(buffer);
411- }
412-
413- void available(MirBuffer* buffer) override
414- {
415- std::unique_lock<std::mutex> lk(mut);
416- if (!handle)
417- {
418- handle = buffer;
419- cv.notify_all();
420- }
421-
422- auto g = f;
423- lk.unlock();
424- if (g)
425- g();
426- }
427-
428- void on_ownership_notification(std::function<void()> const& fn) override
429- {
430- std::unique_lock<std::mutex> lk(mut);
431- f = fn;
432- }
433-
434- MirBufferPackage* package() const override
435- {
436- return mir_buffer_get_buffer_package(handle);
437- }
438-
439- void set_fence(mir::Fd fd) override
440- {
441- if (fence_extensions && fence_extensions->associate_fence)
442- fence_extensions->associate_fence(handle, fd, mir_read_write);
443- }
444-
445- mir::Fd fence() const override
446- {
447- if (fence_extensions && fence_extensions->get_fence)
448- return mir::Fd{fence_extensions->get_fence(handle)};
449- else
450- return mir::Fd{mir::Fd::invalid};
451- }
452-
453-private:
454- MirExtensionFencedBuffersV1 const* fence_extensions = nullptr;
455-
456- std::function<void()> f;
457- MirBuffer* handle = nullptr;
458- std::mutex mut;
459- std::condition_variable cv;
460-};
461-
462 class SurfaceSpec : public mgn::HostSurfaceSpec
463 {
464 public:
465@@ -824,13 +655,13 @@
466 std::shared_ptr<mgn::NativeBuffer> mgn::MirClientHostConnection::create_buffer(
467 mg::BufferProperties const& properties)
468 {
469- return std::make_shared<HostBuffer>(mir_connection, properties);
470+ return std::make_shared<mgn::HostBuffer>(mir_connection, properties);
471 }
472
473 std::shared_ptr<mgn::NativeBuffer> mgn::MirClientHostConnection::create_buffer(
474 geom::Size size, MirPixelFormat format)
475 {
476- return std::make_shared<HostBuffer>(mir_connection, size, format);
477+ return std::make_shared<mgn::HostBuffer>(mir_connection, size, format);
478 }
479
480 std::shared_ptr<mgn::NativeBuffer> mgn::MirClientHostConnection::create_buffer(
481@@ -838,12 +669,12 @@
482 {
483 if (auto ext = mir_extension_gbm_buffer_v1(mir_connection))
484 {
485- return std::make_shared<HostBuffer>(mir_connection, ext, size, native_format, native_flags);
486+ return std::make_shared<mgn::HostBuffer>(mir_connection, ext, size, native_format, native_flags);
487 }
488
489 if (auto ext = mir_extension_android_buffer_v1(mir_connection))
490 {
491- return std::make_shared<HostBuffer>(mir_connection, ext, size, native_format, native_flags);
492+ return std::make_shared<mgn::HostBuffer>(mir_connection, ext, size, native_format, native_flags);
493 }
494
495 BOOST_THROW_EXCEPTION(std::runtime_error("could not create hardware buffer"));
496
497=== added file 'tests/include/mir/test/doubles/mock_client_platform.h'
498--- tests/include/mir/test/doubles/mock_client_platform.h 1970-01-01 00:00:00 +0000
499+++ tests/include/mir/test/doubles/mock_client_platform.h 2017-02-14 17:05:00 +0000
500@@ -0,0 +1,76 @@
501+/*
502+ * Copyright © 2017 Canonical Ltd.
503+ *
504+ * This program is free software: you can redistribute it and/or modify it
505+ * under the terms of the GNU General Public License version 3,
506+ * as published by the Free Software Foundation.
507+ *
508+ * This program is distributed in the hope that it will be useful,
509+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
510+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
511+ * GNU General Public License for more details.
512+ *
513+ * You should have received a copy of the GNU General Public License
514+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
515+ *
516+ * Authored by: Kevin DuBois <kevin.dubois@canonical.com>
517+ */
518+
519+#ifndef MIR_TEST_DOUBLES_MOCK_CLIENT_PLATFOM_H_
520+#define MIR_TEST_DOUBLES_MOCK_CLIENT_PLATFOM_H_
521+
522+#include "stub_client_buffer_factory.h"
523+#include "mir/client_platform.h"
524+#include "mir/client_platform_factory.h"
525+#include <gmock/gmock.h>
526+
527+namespace mir
528+{
529+namespace test
530+{
531+namespace doubles
532+{
533+
534+struct MockClientPlatform : public client::ClientPlatform
535+{
536+ MockClientPlatform()
537+ {
538+ auto native_window = std::make_shared<EGLNativeWindowType>();
539+ *native_window = reinterpret_cast<EGLNativeWindowType>(this);
540+
541+ ON_CALL(*this, create_buffer_factory())
542+ .WillByDefault(testing::Return(std::make_shared<StubClientBufferFactory>()));
543+ ON_CALL(*this, create_egl_native_window(testing::_))
544+ .WillByDefault(testing::Return(native_window));
545+ }
546+
547+ void set_client_context(client::ClientContext* ctx)
548+ {
549+ client_context = ctx;
550+ }
551+
552+ void populate(MirPlatformPackage& pkg) const override
553+ {
554+ client_context->populate_server_package(pkg);
555+ }
556+
557+ MOCK_CONST_METHOD1(convert_native_buffer, MirNativeBuffer*(mir::graphics::NativeBuffer*));
558+ MOCK_CONST_METHOD0(platform_type, MirPlatformType());
559+ MOCK_METHOD1(platform_operation, MirPlatformMessage*(MirPlatformMessage const*));
560+ MOCK_METHOD0(create_buffer_factory, std::shared_ptr<client::ClientBufferFactory>());
561+ MOCK_METHOD2(use_egl_native_window, void(std::shared_ptr<void>, client::EGLNativeSurface*));
562+ MOCK_METHOD1(create_egl_native_window, std::shared_ptr<void>(client::EGLNativeSurface*));
563+ MOCK_METHOD0(create_egl_native_display, std::shared_ptr<EGLNativeDisplayType>());
564+ MOCK_CONST_METHOD2(get_egl_pixel_format, MirPixelFormat(EGLDisplay, EGLConfig));
565+ MOCK_METHOD2(request_interface, void*(char const*, int));
566+ MOCK_CONST_METHOD1(native_format_for, uint32_t(MirPixelFormat));
567+ MOCK_CONST_METHOD2(native_flags_for, uint32_t(MirBufferUsage, mir::geometry::Size));
568+
569+ client::ClientContext* client_context = nullptr;
570+};
571+
572+}
573+}
574+}
575+
576+#endif /* MIR_TEST_DOUBLES_MOCK_CLIENT_PLATFOM_H_ */
577
578=== added file 'tests/include/mir/test/doubles/stub_client_platform_factory.h'
579--- tests/include/mir/test/doubles/stub_client_platform_factory.h 1970-01-01 00:00:00 +0000
580+++ tests/include/mir/test/doubles/stub_client_platform_factory.h 2017-02-14 17:05:00 +0000
581@@ -0,0 +1,50 @@
582+/*
583+ * Copyright © 2017 Canonical Ltd.
584+ *
585+ * This program is free software: you can redistribute it and/or modify it
586+ * under the terms of the GNU General Public License version 3,
587+ * as published by the Free Software Foundation.
588+ *
589+ * This program is distributed in the hope that it will be useful,
590+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
591+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
592+ * GNU General Public License for more details.
593+ *
594+ * You should have received a copy of the GNU General Public License
595+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
596+ *
597+ * Authored by: Kevin DuBois <kevin.dubois@canonical.com>
598+ */
599+
600+#ifndef MIR_TEST_DOUBLES_STUB_CLIENT_PLATFORM_FACTORY_H_
601+#define MIR_TEST_DOUBLES_STUB_CLIENT_PLATFORM_FACTORY_H_
602+
603+#include "mir/client_platform_factory.h"
604+
605+namespace mir
606+{
607+namespace test
608+{
609+namespace doubles
610+{
611+
612+struct StubClientPlatformFactory : public client::ClientPlatformFactory
613+{
614+ StubClientPlatformFactory(std::shared_ptr<client::ClientPlatform> const& platform)
615+ : platform{platform}
616+ {
617+ }
618+
619+ std::shared_ptr<client::ClientPlatform> create_client_platform(client::ClientContext*)
620+ {
621+ return platform;
622+ }
623+
624+ std::shared_ptr<client::ClientPlatform> platform;
625+};
626+
627+}
628+}
629+}
630+
631+#endif /* MIR_TEST_DOUBLES_STUB_CLIENT_PLATFORM_FACTORY_H_ */
632
633=== modified file 'tests/include/mir/test/stub_server_tool.h'
634--- tests/include/mir/test/stub_server_tool.h 2017-02-14 07:05:13 +0000
635+++ tests/include/mir/test/stub_server_tool.h 2017-02-14 17:05:00 +0000
636@@ -123,6 +123,20 @@
637 {
638 done->Run();
639 }
640+ virtual void allocate_buffers(
641+ mir::protobuf::BufferAllocation const* /*request*/,
642+ mir::protobuf::Void* /*response*/,
643+ google::protobuf::Closure* done)
644+ {
645+ done->Run();
646+ }
647+ void release_buffers(
648+ mir::protobuf::BufferRelease const* /*request*/,
649+ mir::protobuf::Void* /*response*/,
650+ google::protobuf::Closure* done)
651+ {
652+ done->Run();
653+ }
654
655 std::string application_name() const
656 {
657
658=== modified file 'tests/unit-tests/client/test_mir_render_surface.cpp'
659--- tests/unit-tests/client/test_mir_render_surface.cpp 2017-02-07 07:13:47 +0000
660+++ tests/unit-tests/client/test_mir_render_surface.cpp 2017-02-14 17:05:00 +0000
661@@ -28,6 +28,8 @@
662
663 #include "mir/test/fake_shared.h"
664 #include "mir/test/doubles/stub_client_buffer_factory.h"
665+#include "mir/test/doubles/stub_client_platform_factory.h"
666+#include "mir/test/doubles/mock_client_platform.h"
667 #include "mir_protobuf.pb.h"
668
669 #include <sys/eventfd.h>
670@@ -102,59 +104,6 @@
671 mir::Fd pollable_fd;
672 };
673
674-struct MockClientPlatform : public mcl::ClientPlatform
675-{
676- MockClientPlatform()
677- {
678- auto native_window = std::make_shared<EGLNativeWindowType>();
679- *native_window = reinterpret_cast<EGLNativeWindowType>(this);
680-
681- ON_CALL(*this, create_buffer_factory())
682- .WillByDefault(Return(std::make_shared<mtd::StubClientBufferFactory>()));
683- ON_CALL(*this, create_egl_native_window(_))
684- .WillByDefault(Return(native_window));
685- }
686-
687- void set_client_context(mcl::ClientContext* ctx)
688- {
689- client_context = ctx;
690- }
691-
692- void populate(MirPlatformPackage& pkg) const override
693- {
694- client_context->populate_server_package(pkg);
695- }
696-
697- MOCK_CONST_METHOD1(convert_native_buffer, MirNativeBuffer*(mir::graphics::NativeBuffer*));
698- MOCK_CONST_METHOD0(platform_type, MirPlatformType());
699- MOCK_METHOD1(platform_operation, MirPlatformMessage*(MirPlatformMessage const*));
700- MOCK_METHOD0(create_buffer_factory, std::shared_ptr<mcl::ClientBufferFactory>());
701- MOCK_METHOD2(use_egl_native_window, void(std::shared_ptr<void>, mcl::EGLNativeSurface*));
702- MOCK_METHOD1(create_egl_native_window, std::shared_ptr<void>(mcl::EGLNativeSurface*));
703- MOCK_METHOD0(create_egl_native_display, std::shared_ptr<EGLNativeDisplayType>());
704- MOCK_CONST_METHOD2(get_egl_pixel_format, MirPixelFormat(EGLDisplay, EGLConfig));
705- MOCK_METHOD2(request_interface, void*(char const*, int));
706- MOCK_CONST_METHOD1(native_format_for, uint32_t(MirPixelFormat));
707- MOCK_CONST_METHOD2(native_flags_for, uint32_t(MirBufferUsage, mir::geometry::Size));
708-
709- mcl::ClientContext* client_context = nullptr;
710-};
711-
712-struct StubClientPlatformFactory : public mcl::ClientPlatformFactory
713-{
714- StubClientPlatformFactory(std::shared_ptr<mcl::ClientPlatform> const& platform)
715- : platform{platform}
716- {
717- }
718-
719- std::shared_ptr<mcl::ClientPlatform> create_client_platform(mcl::ClientContext*)
720- {
721- return platform;
722- }
723-
724- std::shared_ptr<mcl::ClientPlatform> platform;
725-};
726-
727 void connected_callback(MirConnection* /*connection*/, void* /*client_context*/)
728 {
729 }
730@@ -178,7 +127,7 @@
731
732 std::shared_ptr<mcl::ClientPlatformFactory> the_client_platform_factory() override
733 {
734- return std::make_shared<StubClientPlatformFactory>(platform);
735+ return std::make_shared<mtd::StubClientPlatformFactory>(platform);
736 }
737
738 private:
739@@ -190,7 +139,7 @@
740 struct MirRenderSurfaceTest : public testing::Test
741 {
742 MirRenderSurfaceTest()
743- : mock_platform{std::make_shared<testing::NiceMock<MockClientPlatform>>()},
744+ : mock_platform{std::make_shared<testing::NiceMock<mtd::MockClientPlatform>>()},
745 mock_channel{std::make_shared<testing::NiceMock<MockRpcChannel>>()},
746 conf{mock_platform, mock_channel},
747 connection{std::make_shared<MirConnection>(conf)}
748@@ -198,7 +147,7 @@
749 mock_platform->set_client_context(connection.get());
750 }
751
752- std::shared_ptr<testing::NiceMock<MockClientPlatform>> const mock_platform;
753+ std::shared_ptr<testing::NiceMock<mtd::MockClientPlatform>> const mock_platform;
754 std::shared_ptr<testing::NiceMock<MockRpcChannel>> const mock_channel;
755 TestConnectionConfiguration conf;
756 std::shared_ptr<MirConnection> const connection;
757
758=== modified file 'tests/unit-tests/platforms/nested/CMakeLists.txt'
759--- tests/unit-tests/platforms/nested/CMakeLists.txt 2017-01-30 08:13:20 +0000
760+++ tests/unit-tests/platforms/nested/CMakeLists.txt 2017-02-14 17:05:00 +0000
761@@ -6,6 +6,7 @@
762 ${CMAKE_CURRENT_SOURCE_DIR}/test_buffer.cpp
763 ${CMAKE_CURRENT_SOURCE_DIR}/test_nested_display_buffer.cpp
764 ${CMAKE_CURRENT_SOURCE_DIR}/test_ipc_operations.cpp
765+ ${CMAKE_CURRENT_SOURCE_DIR}/test_host_buffer.cpp
766 $<TARGET_OBJECTS:mir-test-doubles-udev>
767 ${MIR_PLATFORM_OBJECTS}
768 ${MIR_SERVER_OBJECTS}
769
770=== added file 'tests/unit-tests/platforms/nested/test_host_buffer.cpp'
771--- tests/unit-tests/platforms/nested/test_host_buffer.cpp 1970-01-01 00:00:00 +0000
772+++ tests/unit-tests/platforms/nested/test_host_buffer.cpp 2017-02-14 17:05:00 +0000
773@@ -0,0 +1,127 @@
774+/*
775+ * Copyright © 2017 Canonical Ltd.
776+ *
777+ * This program is free software: you can redistribute it and/or modify
778+ * it under the terms of the GNU General Public License version 3 as
779+ * published by the Free Software Foundation.
780+ *
781+ * This program is distributed in the hope that it will be useful,
782+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
783+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
784+ * GNU General Public License for more details.
785+ *
786+ * You should have received a copy of the GNU General Public License
787+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
788+ *
789+ * Authored by: Kevin DuBois <kevin.dubois@canonical.com>
790+ */
791+
792+#include "src/server/graphics/nested/host_buffer.h"
793+#include "src/client/default_connection_configuration.h"
794+#include "src/client/mir_connection.h"
795+#include "src/client/buffer_factory.h"
796+#include "src/client/buffer.h"
797+#include "mir/test/stub_server_tool.h"
798+#include "mir/test/test_protobuf_server.h"
799+#include "mir/test/doubles/stub_client_platform_factory.h"
800+#include "mir/test/doubles/mock_client_platform.h"
801+#include "mir/frontend/connector.h"
802+#include <gtest/gtest.h>
803+#include <gmock/gmock.h>
804+#include <fcntl.h>
805+
806+using namespace testing;
807+namespace mgn = mir::graphics::nested;
808+namespace mt = mir::test;
809+namespace mcl = mir::client;
810+namespace mtd = mir::test::doubles;
811+
812+std::unique_ptr<mir::Fd> fd = nullptr;
813+int get_fence(MirBuffer*)
814+{
815+ if (fd)
816+ return *fd;
817+ return -1;
818+}
819+
820+struct TestConnectionConfiguration : mir::client::DefaultConnectionConfiguration
821+{
822+public:
823+
824+ TestConnectionConfiguration(std::string const& socket)
825+ : DefaultConnectionConfiguration(socket)
826+ {
827+ }
828+
829+ std::shared_ptr<mcl::ClientPlatformFactory> the_client_platform_factory() override
830+ {
831+ auto platform = std::make_shared<mtd::MockClientPlatform>();
832+ ON_CALL(*platform, request_interface(StrEq("mir_extension_fenced_buffers"), 1))
833+ .WillByDefault(Return(&fence_ext));
834+ return std::make_shared<mtd::StubClientPlatformFactory>(platform);
835+ }
836+
837+ MirExtensionFencedBuffersV1 fence_ext{get_fence, nullptr, nullptr};
838+
839+ std::shared_ptr<mir::client::AsyncBufferFactory> the_buffer_factory() override
840+ {
841+ struct StubBufferFactory : mcl::AsyncBufferFactory
842+ {
843+ std::shared_ptr<mcl::Buffer> buffer;
844+ std::unique_ptr<mcl::MirBuffer> generate_buffer(mir::protobuf::Buffer const&) override
845+ {
846+ return nullptr;
847+ }
848+ void expect_buffer(
849+ std::shared_ptr<mcl::ClientBufferFactory> const&,
850+ MirConnection* conn, mir::geometry::Size,
851+ MirPixelFormat, MirBufferUsage usage, MirBufferCallback cb, void* ctx) override
852+ {
853+ if (!buffer)
854+ buffer = std::make_shared<mcl::Buffer>(cb, ctx, 1, nullptr, conn, usage);
855+ cb(reinterpret_cast<MirBuffer*>(buffer.get()), ctx);
856+ }
857+ void expect_buffer(
858+ std::shared_ptr<mcl::ClientBufferFactory> const&,
859+ MirConnection*, mir::geometry::Size, uint32_t, uint32_t,
860+ MirBufferCallback, void*) override
861+ {
862+ }
863+ void cancel_requests_with_context(void*) {}
864+ };
865+ return std::make_shared<StubBufferFactory>();
866+ }
867+};
868+
869+struct HostBuffer : Test
870+{
871+ HostBuffer()
872+ {
873+ //MirConnection is hard to stub
874+ std::remove(socket.c_str());
875+ test_server = std::make_shared<mt::TestProtobufServer>(socket, server_tool);
876+ test_server->comm->start();
877+ config = std::make_shared<TestConnectionConfiguration>(socket);
878+ }
879+
880+ std::string const socket { "./test_sock" };
881+ std::shared_ptr<mt::StubServerTool> const server_tool = std::make_shared<mt::StubServerTool>();
882+ std::shared_ptr<mt::TestProtobufServer> test_server;
883+ std::shared_ptr<TestConnectionConfiguration> config;
884+};
885+
886+//LP: #1664562
887+TEST_F(HostBuffer, does_not_own_fd_when_accessing_fence)
888+{
889+ fd = std::make_unique<mir::Fd>( fileno(tmpfile()) );
890+
891+ MirConnection connection{*config};
892+ connection.connect("", [](auto*, auto*){}, nullptr)->wait_for_all();
893+ mgn::HostBuffer buffer(&connection, mir::geometry::Size{1,1}, mir_pixel_format_abgr_8888);
894+ {
895+ auto fence = buffer.fence();
896+ EXPECT_THAT(fence, Eq(*fd));
897+ }
898+ EXPECT_THAT(fcntl(*fd, F_GETFD), Eq(0));
899+ fd.reset();
900+}

Subscribers

People subscribed via source and target branches