Mir

Merge lp:~vanvugt/mir/rotate-display-buffer into lp:mir

Proposed by Daniel van Vugt
Status: Merged
Approved by: Chris Halse Rogers
Approved revision: no longer in the source branch.
Merged at revision: 1341
Proposed branch: lp:~vanvugt/mir/rotate-display-buffer
Merge into: lp:mir
Diff against target: 719 lines (+434/-9)
17 files modified
include/platform/mir/graphics/display_buffer.h (+10/-0)
include/test/mir_test_doubles/mock_display_buffer.h (+1/-0)
include/test/mir_test_doubles/null_display_buffer.h (+1/-0)
src/platform/graphics/android/android_display.cpp (+13/-0)
src/platform/graphics/android/display_buffer.cpp (+27/-2)
src/platform/graphics/android/display_buffer.h (+3/-0)
src/platform/graphics/mesa/display.cpp (+18/-3)
src/platform/graphics/mesa/display_buffer.cpp (+25/-2)
src/platform/graphics/mesa/display_buffer.h (+4/-0)
src/server/graphics/nested/nested_output.cpp (+10/-1)
src/server/graphics/nested/nested_output.h (+1/-0)
src/server/graphics/offscreen/display_buffer.cpp (+10/-1)
src/server/graphics/offscreen/display_buffer.h (+1/-0)
tests/unit-tests/graphics/android/test_hwc_display.cpp (+50/-0)
tests/unit-tests/graphics/mesa/CMakeLists.txt (+1/-0)
tests/unit-tests/graphics/mesa/test_display_buffer.cpp (+236/-0)
tests/unit-tests/graphics/offscreen/test_offscreen_display.cpp (+23/-0)
To merge this branch: bzr merge lp:~vanvugt/mir/rotate-display-buffer
Reviewer Review Type Date Requested Status
Chris Halse Rogers Approve
Kevin DuBois (community) ok for now Approve
Alan Griffiths Approve
PS Jenkins bot (community) continuous-integration Approve
Review via email: mp+202277@code.launchpad.net

Commit message

Add DisplayBuffer::orientation(), to tell the Renderer if we need it to do
screen rotation in GL (for platforms which don't implement rotation natively)

Description of the change

Another stepping stone on the path to screen rotation. The aforementioned Renderer work will be proposed separately, to keep reviews simple. Although some of this proposal may not make sense to the reader without it, so if you really desperately want me to then I will merge the Renderer work into this.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Andreas Pokorny (andreas-pokorny) wrote :

I have only two minor changes of improvement that would make the intent clearer and be less verbose:

168 + std::swap(width,height);

204 + fb_width = area.size.width.as_uint32_t();
205 + fb_height = area.size.height.as_uint32_t();
206 + if (rotation == mir_orientation_left || rotation == mir_orientation_right)
207 + std::swap(fb_width, fb_height);

But no blocker compared to the unit test issues on mesa.

Revision history for this message
Kevin DuBois (kdub) wrote :

I'd like to avoid the dynamic_cast in l75 if possible...

Perhaps we could just keep the state of the orientation in mga::AndroidDisplay (and the android display configuration class). Seems a bit more palatable until the android classes improve here. Don't want to block though, abstaining.

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

All fixed.

Kevin:
I prototyped orient() in the DisplayBuffer interface to avoid the dynamic cast. Unfortunately that creates a bigger problem of then "contractually" having to implement orient() for the more complex mesa::DisplayBuffer, which is otherwise unnecessary. The problem only exists because AndroidDisplay refuses to admit its display_buffer is android::DisplayBuffer, for the purposes of stubbing in tests. Though you can see AndroidDisplay already employs dynamic_cast...
  Also, putting orientation() in AndroidDisplay would not work. The Renderer only has access to the DisplayBuffer interface. Which is clean and I'd like to keep it that way.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

7 #include <mir/geometry/rectangle.h>
8 +#include <mir_toolkit/common.h>

This include style is in a small minority:

$ grep "#include <mir" `find include -name \*.h` | wc -l
15
$ grep "#include \"mir" `find include -name \*.h` | wc -l
212

Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

OK

review: Approve
Revision history for this message
Kevin DuBois (kdub) wrote :

> All fixed.
>
> Kevin:
> I prototyped orient() in the DisplayBuffer interface to avoid the dynamic
> cast. Unfortunately that creates a bigger problem of then "contractually"
> having to implement orient() for the more complex mesa::DisplayBuffer, which
> is otherwise unnecessary. The problem only exists because AndroidDisplay
> refuses to admit its display_buffer is android::DisplayBuffer, for the
> purposes of stubbing in tests. Though you can see AndroidDisplay already
> employs dynamic_cast...
> Also, putting orientation() in AndroidDisplay would not work. The Renderer
> only has access to the DisplayBuffer interface. Which is clean and I'd like to
> keep it that way.

After seeing the other MP's today, I see why it wouldn't work.
In as far as reconfiguring the display goes, the android classes need a bit of work with the already-in-place mode() function, so I don't object to doing this with the orientation. (although I might redo the orientation and mode state to live solely within the DisplayDevice classes in the future.)

review: Approve (ok for now)
Revision history for this message
Chris Halse Rogers (raof) wrote :

Looks fine to me

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'include/platform/mir/graphics/display_buffer.h'
2--- include/platform/mir/graphics/display_buffer.h 2014-01-17 23:07:03 +0000
3+++ include/platform/mir/graphics/display_buffer.h 2014-01-21 07:20:58 +0000
4@@ -21,6 +21,7 @@
5
6 #include "renderable.h"
7 #include <mir/geometry/rectangle.h>
8+#include <mir_toolkit/common.h>
9
10 #include <memory>
11 #include <functional>
12@@ -63,6 +64,15 @@
13 virtual bool can_bypass() const = 0;
14 virtual void post_update(std::shared_ptr<Buffer> /* bypass_buf */) {}
15
16+ /** Returns the orientation of the display buffer relative to how the
17+ * user should see it (the orientation of the output).
18+ * This tells us how much (if any) rotation the renderer needs to do.
19+ * If your DisplayBuffer can do the rotation itself then this will
20+ * always return mir_orientation_normal. If the DisplayBuffer does not
21+ * implement the rotation itself then this function will return the
22+ * amount of rotation the renderer must do to make things "look right".
23+ */
24+ virtual MirOrientation orientation() const = 0;
25
26 protected:
27 DisplayBuffer() = default;
28
29=== modified file 'include/test/mir_test_doubles/mock_display_buffer.h'
30--- include/test/mir_test_doubles/mock_display_buffer.h 2014-01-17 19:42:09 +0000
31+++ include/test/mir_test_doubles/mock_display_buffer.h 2014-01-21 07:20:58 +0000
32@@ -40,6 +40,7 @@
33 MOCK_CONST_METHOD0(can_bypass, bool());
34 MOCK_METHOD2(render_and_post_update, void(std::list<graphics::Renderable> const&,
35 std::function<void(graphics::Renderable const&)> const&));
36+ MOCK_CONST_METHOD0(orientation, MirOrientation());
37 };
38
39 }
40
41=== modified file 'include/test/mir_test_doubles/null_display_buffer.h'
42--- include/test/mir_test_doubles/null_display_buffer.h 2014-01-17 19:42:09 +0000
43+++ include/test/mir_test_doubles/null_display_buffer.h 2014-01-21 07:20:58 +0000
44@@ -39,6 +39,7 @@
45 void render_and_post_update(
46 std::list<graphics::Renderable> const&,
47 std::function<void(graphics::Renderable const&)> const&) {}
48+ MirOrientation orientation() const override { return mir_orientation_normal; }
49 };
50
51 }
52
53=== modified file 'src/platform/graphics/android/android_display.cpp'
54--- src/platform/graphics/android/android_display.cpp 2014-01-13 06:12:33 +0000
55+++ src/platform/graphics/android/android_display.cpp 2014-01-21 07:20:58 +0000
56@@ -59,12 +59,25 @@
57
58 void mga::AndroidDisplay::configure(mg::DisplayConfiguration const& configuration)
59 {
60+ MirOrientation orientation = mir_orientation_normal;
61+
62 configuration.for_each_output([&](mg::DisplayConfigurationOutput const& output)
63 {
64 // TODO: Properly support multiple outputs
65 display_device->mode(output.power_mode);
66+ orientation = output.orientation;
67 });
68 current_configuration = dynamic_cast<mga::AndroidDisplayConfiguration const&>(configuration);
69+
70+ /*
71+ * It's tempting to put orient() into the base class and so avoid this
72+ * cast, but we only need it in the Android implementation right now.
73+ */
74+ if (android::DisplayBuffer* db =
75+ dynamic_cast<mga::DisplayBuffer*>(display_buffer.get()))
76+ {
77+ db->orient(orientation);
78+ }
79 }
80
81 void mga::AndroidDisplay::register_configuration_change_handler(
82
83=== modified file 'src/platform/graphics/android/display_buffer.cpp'
84--- src/platform/graphics/android/display_buffer.cpp 2014-01-20 16:38:54 +0000
85+++ src/platform/graphics/android/display_buffer.cpp 2014-01-21 07:20:58 +0000
86@@ -23,6 +23,7 @@
87 #include <functional>
88 #include <boost/throw_exception.hpp>
89 #include <stdexcept>
90+#include <algorithm>
91
92 namespace mga=mir::graphics::android;
93 namespace geom=mir::geometry;
94@@ -35,13 +36,21 @@
95 : fb_bundle{fb_bundle},
96 display_device{display_device},
97 native_window{native_window},
98- gl_context{shared_gl_context, std::bind(mga::create_window_surface, std::placeholders::_1, std::placeholders::_2, native_window.get())}
99+ gl_context{shared_gl_context, std::bind(mga::create_window_surface, std::placeholders::_1, std::placeholders::_2, native_window.get())},
100+ rotation{mir_orientation_normal}
101 {
102 }
103
104 geom::Rectangle mga::DisplayBuffer::view_area() const
105 {
106- return {geom::Point{}, fb_bundle->fb_size()};
107+ auto const& size = fb_bundle->fb_size();
108+ int width = size.width.as_int();
109+ int height = size.height.as_int();
110+
111+ if (rotation == mir_orientation_left || rotation == mir_orientation_right)
112+ std::swap(width, height);
113+
114+ return {{0,0}, {width,height}};
115 }
116
117 void mga::DisplayBuffer::make_current()
118@@ -92,3 +101,19 @@
119 {
120 return false;
121 }
122+
123+MirOrientation mga::DisplayBuffer::orientation() const
124+{
125+ /*
126+ * android::DisplayBuffer is aways created with physical width/height
127+ * (not rotated). So we just need to pass through the desired rotation
128+ * and let the renderer do it.
129+ * If and when we choose to implement HWC rotation, this may change.
130+ */
131+ return rotation;
132+}
133+
134+void mga::DisplayBuffer::orient(MirOrientation rot)
135+{
136+ rotation = rot;
137+}
138
139=== modified file 'src/platform/graphics/android/display_buffer.h'
140--- src/platform/graphics/android/display_buffer.h 2014-01-20 16:38:54 +0000
141+++ src/platform/graphics/android/display_buffer.h 2014-01-21 07:20:58 +0000
142@@ -50,6 +50,8 @@
143 void render_and_post_update(
144 std::list<Renderable> const& renderlist,
145 std::function<void(Renderable const&)> const& render_fn);
146+ MirOrientation orientation() const override;
147+ void orient(MirOrientation);
148
149 private:
150 void render_and_post();
151@@ -59,6 +61,7 @@
152 std::shared_ptr<ANativeWindow> const native_window;
153 GLContext gl_context;
154 bool prepared;
155+ MirOrientation rotation;
156 };
157
158 }
159
160=== modified file 'src/platform/graphics/mesa/display.cpp'
161--- src/platform/graphics/mesa/display.cpp 2014-01-13 06:12:33 +0000
162+++ src/platform/graphics/mesa/display.cpp 2014-01-21 07:20:58 +0000
163@@ -36,6 +36,7 @@
164 #include <boost/exception/errinfo_errno.hpp>
165
166 #include <stdexcept>
167+#include <algorithm>
168
169 namespace mgm = mir::graphics::mesa;
170 namespace mg = mir::graphics;
171@@ -147,6 +148,7 @@
172 {
173 auto bounding_rect = group.bounding_rectangle();
174 std::vector<std::shared_ptr<KMSOutput>> kms_outputs;
175+ MirOrientation orientation = mir_orientation_normal;
176
177 group.for_each_output([&](DisplayConfigurationOutput const& conf_output)
178 {
179@@ -158,17 +160,30 @@
180 kms_output->configure(conf_output.top_left - bounding_rect.top_left, mode_index);
181 kms_output->set_power_mode(conf_output.power_mode);
182 kms_outputs.push_back(kms_output);
183+
184+ /*
185+ * Presently OverlappingOutputGroup guarantees all grouped
186+ * outputs have the same orientation.
187+ */
188+ orientation = conf_output.orientation;
189 });
190
191- auto surface =
192- platform->gbm.create_scanout_surface(bounding_rect.size.width.as_uint32_t(),
193- bounding_rect.size.height.as_uint32_t());
194+ uint32_t width = bounding_rect.size.width.as_uint32_t();
195+ uint32_t height = bounding_rect.size.height.as_uint32_t();
196+ if (orientation == mir_orientation_left ||
197+ orientation == mir_orientation_right)
198+ {
199+ std::swap(width, height);
200+ }
201+
202+ auto surface = platform->gbm.create_scanout_surface(width, height);
203
204 std::unique_ptr<DisplayBuffer> db{
205 new DisplayBuffer{platform, listener,
206 kms_outputs,
207 std::move(surface),
208 bounding_rect,
209+ orientation,
210 shared_egl.context()}};
211
212 display_buffers_new.push_back(std::move(db));
213
214=== modified file 'src/platform/graphics/mesa/display_buffer.cpp'
215--- src/platform/graphics/mesa/display_buffer.cpp 2014-01-20 16:38:54 +0000
216+++ src/platform/graphics/mesa/display_buffer.cpp 2014-01-21 07:20:58 +0000
217@@ -100,6 +100,7 @@
218 std::vector<std::shared_ptr<KMSOutput>> const& outputs,
219 GBMSurfaceUPtr surface_gbm_param,
220 geom::Rectangle const& area,
221+ MirOrientation rot,
222 EGLContext shared_context)
223 : last_flipped_bufobj{nullptr},
224 platform(platform),
225@@ -108,8 +109,22 @@
226 outputs(outputs),
227 surface_gbm{std::move(surface_gbm_param)},
228 area(area),
229+ rotation(rot),
230 needs_set_crtc{false}
231 {
232+ uint32_t area_width = area.size.width.as_uint32_t();
233+ uint32_t area_height = area.size.height.as_uint32_t();
234+ if (rotation == mir_orientation_left || rotation == mir_orientation_right)
235+ {
236+ fb_width = area_height;
237+ fb_height = area_width;
238+ }
239+ else
240+ {
241+ fb_width = area_width;
242+ fb_height = area_height;
243+ }
244+
245 egl.setup(platform->gbm, surface_gbm.get(), shared_context);
246
247 listener->report_successful_setup_of_native_resources();
248@@ -165,7 +180,14 @@
249
250 bool mgm::DisplayBuffer::can_bypass() const
251 {
252- return true;
253+ return (rotation == mir_orientation_normal);
254+}
255+
256+
257+MirOrientation mgm::DisplayBuffer::orientation() const
258+{
259+ // Tell the renderer to do the rotation, since we're not doing it here.
260+ return rotation;
261 }
262
263 void mgm::DisplayBuffer::render_and_post_update(
264@@ -276,7 +298,7 @@
265 auto stride = gbm_bo_get_stride(bo);
266
267 /* Create a KMS FB object with the gbm_bo attached to it. */
268- auto ret = drmModeAddFB(drm.fd, area.size.width.as_uint32_t(), area.size.height.as_uint32_t(),
269+ auto ret = drmModeAddFB(drm.fd, fb_width, fb_height,
270 24, 32, stride, handle, &fb_id);
271 if (ret)
272 return nullptr;
273@@ -331,3 +353,4 @@
274 {
275 needs_set_crtc = true;
276 }
277+
278
279=== modified file 'src/platform/graphics/mesa/display_buffer.h'
280--- src/platform/graphics/mesa/display_buffer.h 2014-01-20 16:38:54 +0000
281+++ src/platform/graphics/mesa/display_buffer.h 2014-01-21 07:20:58 +0000
282@@ -48,6 +48,7 @@
283 std::vector<std::shared_ptr<KMSOutput>> const& outputs,
284 GBMSurfaceUPtr surface_gbm,
285 geometry::Rectangle const& area,
286+ MirOrientation rot,
287 EGLContext shared_context);
288 ~DisplayBuffer();
289
290@@ -60,6 +61,7 @@
291 void post_update(std::shared_ptr<graphics::Buffer> bypass_buf) override;
292 void render_and_post_update(std::list<Renderable> const& renderlist,
293 std::function<void(Renderable const&)> const& render_fn);
294+ MirOrientation orientation() const override;
295 void schedule_set_crtc();
296
297 private:
298@@ -77,6 +79,8 @@
299 GBMSurfaceUPtr surface_gbm;
300 helpers::EGLHelper egl;
301 geometry::Rectangle area;
302+ uint32_t fb_width, fb_height;
303+ MirOrientation rotation;
304 std::atomic<bool> needs_set_crtc;
305 };
306
307
308=== modified file 'src/server/graphics/nested/nested_output.cpp'
309--- src/server/graphics/nested/nested_output.cpp 2014-01-20 16:38:54 +0000
310+++ src/server/graphics/nested/nested_output.cpp 2014-01-21 07:20:58 +0000
311@@ -86,7 +86,16 @@
312 std::list<Renderable> const&,
313 std::function<void(Renderable const&)> const&)
314 {
315-}
316+}
317+
318+MirOrientation mgn::detail::NestedOutput::orientation() const
319+{
320+ /*
321+ * Always normal orientation. The real rotation is handled by the
322+ * native display.
323+ */
324+ return mir_orientation_normal;
325+}
326
327 mgn::detail::NestedOutput::~NestedOutput() noexcept
328 {
329
330=== modified file 'src/server/graphics/nested/nested_output.h'
331--- src/server/graphics/nested/nested_output.h 2014-01-20 16:38:54 +0000
332+++ src/server/graphics/nested/nested_output.h 2014-01-21 07:20:58 +0000
333@@ -64,6 +64,7 @@
334 void release_current() override;
335 void post_update() override;
336 virtual bool can_bypass() const override;
337+ MirOrientation orientation() const override;
338
339 void render_and_post_update(
340 std::list<Renderable> const& renderlist,
341
342=== modified file 'src/server/graphics/offscreen/display_buffer.cpp'
343--- src/server/graphics/offscreen/display_buffer.cpp 2014-01-20 16:38:54 +0000
344+++ src/server/graphics/offscreen/display_buffer.cpp 2014-01-21 07:20:58 +0000
345@@ -153,4 +153,13 @@
346 std::list<Renderable> const&,
347 std::function<void(Renderable const&)> const&)
348 {
349-}
350+}
351+
352+MirOrientation mgo::DisplayBuffer::orientation() const
353+{
354+ /*
355+ * The display buffer's already constructed with rotated dimensions,
356+ * so nothing more to do.
357+ */
358+ return mir_orientation_normal;
359+}
360
361=== modified file 'src/server/graphics/offscreen/display_buffer.h'
362--- src/server/graphics/offscreen/display_buffer.h 2014-01-17 19:42:09 +0000
363+++ src/server/graphics/offscreen/display_buffer.h 2014-01-21 07:20:58 +0000
364@@ -68,6 +68,7 @@
365 void post_update();
366
367 bool can_bypass() const;
368+ MirOrientation orientation() const override;
369
370 void render_and_post_update(
371 std::list<Renderable> const& renderlist,
372
373=== modified file 'tests/unit-tests/graphics/android/test_hwc_display.cpp'
374--- tests/unit-tests/graphics/android/test_hwc_display.cpp 2014-01-20 16:38:54 +0000
375+++ tests/unit-tests/graphics/android/test_hwc_display.cpp 2014-01-21 07:20:58 +0000
376@@ -142,6 +142,56 @@
377 });
378 }
379
380+TEST_F(AndroidDisplayBufferTest, defaults_to_normal_orientation)
381+{
382+ mga::DisplayBuffer db(mock_fb_bundle, mock_display_device, native_window,
383+ *gl_context);
384+
385+ EXPECT_EQ(mir_orientation_normal, db.orientation());
386+}
387+
388+TEST_F(AndroidDisplayBufferTest, orientation_is_passed_through)
389+{
390+ mga::DisplayBuffer db(mock_fb_bundle, mock_display_device, native_window,
391+ *gl_context);
392+
393+ for (auto const& ori : {mir_orientation_normal,
394+ mir_orientation_left,
395+ mir_orientation_right,
396+ mir_orientation_inverted})
397+ {
398+ db.orient(ori);
399+ EXPECT_EQ(ori, db.orientation());
400+ }
401+}
402+
403+TEST_F(AndroidDisplayBufferTest, rotation_transposes_dimensions)
404+{
405+ using namespace testing;
406+
407+ int const width = 123;
408+ int const height = 456;
409+ geom::Size const normal{width, height};
410+ geom::Size const transposed{height, width};
411+
412+ EXPECT_CALL(*mock_fb_bundle, fb_size())
413+ .WillRepeatedly(Return(normal));
414+
415+ mga::DisplayBuffer db(mock_fb_bundle, mock_display_device, native_window,
416+ *gl_context);
417+
418+ EXPECT_EQ(normal, db.view_area().size);
419+
420+ db.orient(mir_orientation_right);
421+ EXPECT_EQ(transposed, db.view_area().size);
422+
423+ db.orient(mir_orientation_inverted);
424+ EXPECT_EQ(normal, db.view_area().size);
425+
426+ db.orient(mir_orientation_left);
427+ EXPECT_EQ(transposed, db.view_area().size);
428+}
429+
430 TEST_F(AndroidDisplayBufferTest, test_db_forwards_size_along)
431 {
432 using namespace testing;
433
434=== modified file 'tests/unit-tests/graphics/mesa/CMakeLists.txt'
435--- tests/unit-tests/graphics/mesa/CMakeLists.txt 2014-01-13 06:12:33 +0000
436+++ tests/unit-tests/graphics/mesa/CMakeLists.txt 2014-01-21 07:20:58 +0000
437@@ -3,6 +3,7 @@
438 ${CMAKE_CURRENT_SOURCE_DIR}/test_gbm_buffer.cpp
439 ${CMAKE_CURRENT_SOURCE_DIR}/test_buffer_allocator.cpp
440 ${CMAKE_CURRENT_SOURCE_DIR}/test_display.cpp
441+ ${CMAKE_CURRENT_SOURCE_DIR}/test_display_buffer.cpp
442 ${CMAKE_CURRENT_SOURCE_DIR}/test_display_multi_monitor.cpp
443 ${CMAKE_CURRENT_SOURCE_DIR}/test_display_configuration.cpp
444 ${CMAKE_CURRENT_SOURCE_DIR}/test_internal_client.cpp
445
446=== added file 'tests/unit-tests/graphics/mesa/test_display_buffer.cpp'
447--- tests/unit-tests/graphics/mesa/test_display_buffer.cpp 1970-01-01 00:00:00 +0000
448+++ tests/unit-tests/graphics/mesa/test_display_buffer.cpp 2014-01-21 07:20:58 +0000
449@@ -0,0 +1,236 @@
450+/*
451+ * Copyright © 2014 Canonical Ltd.
452+ *
453+ * This program is free software: you can redistribute it and/or modify
454+ * it under the terms of the GNU General Public License version 3 as
455+ * published by the Free Software Foundation.
456+ *
457+ * This program is distributed in the hope that it will be useful,
458+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
459+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
460+ * GNU General Public License for more details.
461+ *
462+ * You should have received a copy of the GNU General Public License
463+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
464+ *
465+ * Authored by: Daniel van Vugt <daniel.van.vugt@canonical.com>
466+ */
467+#include "src/platform/graphics/mesa/platform.h"
468+#include "src/platform/graphics/mesa/display_buffer.h"
469+#include "mir/graphics/null_display_report.h"
470+#include "mir_test_doubles/mock_egl.h"
471+#include "mir_test_doubles/mock_gl.h"
472+#include "mir_test_doubles/null_platform.h"
473+#include "mir_test_doubles/null_virtual_terminal.h"
474+#include "mir_test_doubles/mock_drm.h"
475+#include "mir_test_doubles/mock_gbm.h"
476+#include "mir_test_framework/udev_environment.h"
477+
478+#include <gtest/gtest.h>
479+#include <gmock/gmock.h>
480+#include <gbm.h>
481+
482+using namespace testing;
483+using namespace mir;
484+using namespace std;
485+using namespace mir::test::doubles;
486+using namespace mir::mir_test_framework;
487+
488+class MesaDisplayBufferTest : public Test
489+{
490+public:
491+ MesaDisplayBufferTest()
492+ {
493+ ON_CALL(mock_egl, eglChooseConfig(_,_,_,1,_))
494+ .WillByDefault(DoAll(SetArgPointee<2>(mock_egl.fake_configs[0]),
495+ SetArgPointee<4>(1),
496+ Return(EGL_TRUE)));
497+
498+ ON_CALL(mock_egl, eglQueryString(_,EGL_EXTENSIONS))
499+ .WillByDefault(Return("EGL_KHR_image "
500+ "EGL_KHR_image_base "
501+ "EGL_MESA_drm_image"));
502+
503+ ON_CALL(mock_gl, glGetString(GL_EXTENSIONS))
504+ .WillByDefault(Return(reinterpret_cast<const GLubyte*>(
505+ "GL_OES_texture_npot "
506+ "GL_OES_EGL_image")));
507+
508+ fake_bo = reinterpret_cast<gbm_bo*>(123);
509+ ON_CALL(mock_gbm, gbm_surface_lock_front_buffer(_))
510+ .WillByDefault(Return(fake_bo));
511+ fake_handle.u32 = 123;
512+ ON_CALL(mock_gbm, gbm_bo_get_handle(_))
513+ .WillByDefault(Return(fake_handle));
514+ ON_CALL(mock_gbm, gbm_bo_get_stride(_))
515+ .WillByDefault(Return(456));
516+
517+ fake_devices.add_standard_drm_devices();
518+ }
519+
520+ // The platform has an implicit dependency on mock_gbm etc so must be
521+ // reconstructed locally to ensure its lifetime is shorter than mock_gbm.
522+ shared_ptr<graphics::mesa::Platform> create_platform()
523+ {
524+ return make_shared<graphics::mesa::Platform>(
525+ make_shared<graphics::NullDisplayReport>(),
526+ make_shared<NullVirtualTerminal>());
527+ }
528+
529+protected:
530+ NiceMock<MockGBM> mock_gbm;
531+ NiceMock<MockEGL> mock_egl;
532+ NiceMock<MockGL> mock_gl;
533+ NiceMock<MockDRM> mock_drm;
534+ gbm_bo* fake_bo;
535+ gbm_bo_handle fake_handle;
536+ UdevEnvironment fake_devices;
537+};
538+
539+TEST_F(MesaDisplayBufferTest, unrotated_view_area_is_untouched)
540+{
541+ geometry::Rectangle const area{{12,34}, {56,78}};
542+
543+ graphics::mesa::DisplayBuffer db(
544+ create_platform(),
545+ make_shared<graphics::NullDisplayReport>(),
546+ {},
547+ nullptr,
548+ area,
549+ mir_orientation_normal,
550+ mock_egl.fake_egl_context);
551+
552+ EXPECT_EQ(area, db.view_area());
553+}
554+
555+TEST_F(MesaDisplayBufferTest, normal_orientation_can_bypass)
556+{
557+ geometry::Rectangle const area{{12,34}, {56,78}};
558+
559+ graphics::mesa::DisplayBuffer db(
560+ create_platform(),
561+ make_shared<graphics::NullDisplayReport>(),
562+ {},
563+ nullptr,
564+ area,
565+ mir_orientation_normal,
566+ mock_egl.fake_egl_context);
567+
568+ EXPECT_TRUE(db.can_bypass());
569+}
570+
571+TEST_F(MesaDisplayBufferTest, rotated_cannot_bypass)
572+{
573+ geometry::Rectangle const area{{12,34}, {56,78}};
574+
575+ graphics::mesa::DisplayBuffer db(
576+ create_platform(),
577+ make_shared<graphics::NullDisplayReport>(),
578+ {},
579+ nullptr,
580+ area,
581+ mir_orientation_right,
582+ mock_egl.fake_egl_context);
583+
584+ EXPECT_FALSE(db.can_bypass());
585+}
586+
587+TEST_F(MesaDisplayBufferTest, orientation_not_implemented_internally)
588+{
589+ geometry::Rectangle const area{{12,34}, {56,78}};
590+
591+ graphics::mesa::DisplayBuffer db(
592+ create_platform(),
593+ make_shared<graphics::NullDisplayReport>(),
594+ {},
595+ nullptr,
596+ area,
597+ mir_orientation_left,
598+ mock_egl.fake_egl_context);
599+
600+ EXPECT_EQ(mir_orientation_left, db.orientation());
601+}
602+
603+TEST_F(MesaDisplayBufferTest, normal_rotation_constructs_normal_fb)
604+{
605+ int const width = 56;
606+ int const height = 78;
607+ geometry::Rectangle const area{{12,34}, {width,height}};
608+
609+ EXPECT_CALL(mock_gbm, gbm_bo_get_user_data(_))
610+ .WillOnce(Return((void*)0));
611+ EXPECT_CALL(mock_drm, drmModeAddFB(_, width, height, _, _, _, _, _))
612+ .Times(1);
613+
614+ graphics::mesa::DisplayBuffer db(
615+ create_platform(),
616+ make_shared<graphics::NullDisplayReport>(),
617+ {},
618+ nullptr,
619+ area,
620+ mir_orientation_normal,
621+ mock_egl.fake_egl_context);
622+}
623+
624+TEST_F(MesaDisplayBufferTest, left_rotation_constructs_transposed_fb)
625+{
626+ int const width = 56;
627+ int const height = 78;
628+ geometry::Rectangle const area{{12,34}, {width,height}};
629+
630+ EXPECT_CALL(mock_gbm, gbm_bo_get_user_data(_))
631+ .WillOnce(Return((void*)0));
632+ EXPECT_CALL(mock_drm, drmModeAddFB(_, height, width, _, _, _, _, _))
633+ .Times(1);
634+
635+ graphics::mesa::DisplayBuffer db(
636+ create_platform(),
637+ make_shared<graphics::NullDisplayReport>(),
638+ {},
639+ nullptr,
640+ area,
641+ mir_orientation_left,
642+ mock_egl.fake_egl_context);
643+}
644+
645+TEST_F(MesaDisplayBufferTest, inverted_rotation_constructs_normal_fb)
646+{
647+ int const width = 56;
648+ int const height = 78;
649+ geometry::Rectangle const area{{12,34}, {width,height}};
650+
651+ EXPECT_CALL(mock_gbm, gbm_bo_get_user_data(_))
652+ .WillOnce(Return((void*)0));
653+ EXPECT_CALL(mock_drm, drmModeAddFB(_, width, height, _, _, _, _, _))
654+ .Times(1);
655+
656+ graphics::mesa::DisplayBuffer db(
657+ create_platform(),
658+ make_shared<graphics::NullDisplayReport>(),
659+ {},
660+ nullptr,
661+ area,
662+ mir_orientation_inverted,
663+ mock_egl.fake_egl_context);
664+}
665+
666+TEST_F(MesaDisplayBufferTest, right_rotation_constructs_transposed_fb)
667+{
668+ int const width = 56;
669+ int const height = 78;
670+ geometry::Rectangle const area{{12,34}, {width,height}};
671+
672+ EXPECT_CALL(mock_gbm, gbm_bo_get_user_data(_))
673+ .WillOnce(Return((void*)0));
674+ EXPECT_CALL(mock_drm, drmModeAddFB(_, height, width, _, _, _, _, _))
675+ .Times(1);
676+
677+ graphics::mesa::DisplayBuffer db(
678+ create_platform(),
679+ make_shared<graphics::NullDisplayReport>(),
680+ {},
681+ nullptr,
682+ area,
683+ mir_orientation_right,
684+ mock_egl.fake_egl_context);
685+}
686
687=== modified file 'tests/unit-tests/graphics/offscreen/test_offscreen_display.cpp'
688--- tests/unit-tests/graphics/offscreen/test_offscreen_display.cpp 2013-11-18 12:35:14 +0000
689+++ tests/unit-tests/graphics/offscreen/test_offscreen_display.cpp 2014-01-21 07:20:58 +0000
690@@ -83,6 +83,29 @@
691 std::make_shared<mg::NullDisplayReport>()};
692 }
693
694+TEST_F(OffscreenDisplayTest, orientation_normal)
695+{
696+ using namespace ::testing;
697+
698+ EGLNativeDisplayType const native_display{
699+ reinterpret_cast<EGLNativeDisplayType>(0x12345)};
700+
701+ mgo::Display display{
702+ std::make_shared<StubBasicPlatform>(native_display),
703+ std::make_shared<mg::DefaultDisplayConfigurationPolicy>(),
704+ std::make_shared<mg::NullDisplayReport>()};
705+
706+ int count = 0;
707+ display.for_each_display_buffer(
708+ [&](mg::DisplayBuffer& db)
709+ {
710+ ++count;
711+ EXPECT_EQ(mir_orientation_normal, db.orientation());
712+ });
713+
714+ EXPECT_TRUE(count);
715+}
716+
717 TEST_F(OffscreenDisplayTest, makes_fbo_current_rendering_target)
718 {
719 using namespace ::testing;

Subscribers

People subscribed via source and target branches