Merge lp:~andreas-pokorny/mir/add-display-configuration-output-assembly-to-display-device into lp:mir
- add-display-configuration-output-assembly-to-display-device
- Merge into development-branch
Status: | Rejected |
---|---|
Rejected by: | Andreas Pokorny |
Proposed branch: | lp:~andreas-pokorny/mir/add-display-configuration-output-assembly-to-display-device |
Merge into: | lp:mir |
Diff against target: |
899 lines (+608/-23) 18 files modified
src/platform/graphics/android/CMakeLists.txt (+1/-0) src/platform/graphics/android/display_configuration_utilities.cpp (+57/-0) src/platform/graphics/android/display_configuration_utilities.h (+35/-0) src/platform/graphics/android/display_device.h (+2/-0) src/platform/graphics/android/fb_device.cpp (+18/-5) src/platform/graphics/android/fb_device.h (+1/-0) src/platform/graphics/android/hwc_device.cpp (+116/-0) src/platform/graphics/android/hwc_device.h (+1/-0) src/platform/graphics/android/hwc_fb_device.cpp (+9/-0) src/platform/graphics/android/hwc_fb_device.h (+1/-0) src/platform/graphics/android/hwc_wrapper.h (+13/-0) src/platform/graphics/android/real_hwc_wrapper.cpp (+45/-0) src/platform/graphics/android/real_hwc_wrapper.h (+2/-0) tests/include/mir_test_doubles/mock_display_device.h (+1/-0) tests/include/mir_test_doubles/mock_fb_hal_device.h (+11/-5) tests/include/mir_test_doubles/mock_hwc_device_wrapper.h (+3/-0) tests/unit-tests/graphics/android/test_fb_device.cpp (+46/-1) tests/unit-tests/graphics/android/test_hwc_common_device.cpp (+246/-12) |
To merge this branch: | bzr merge lp:~andreas-pokorny/mir/add-display-configuration-output-assembly-to-display-device |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot (community) | continuous-integration | Needs Fixing | |
Kevin DuBois (community) | Needs Fixing | ||
Review via email: mp+239978@code.launchpad.net |
Commit message
Add means to query display output configuration from DisplayDevice
This adds methods to DisplayDevice and HwcWrapper to assemble a DisplayConfigur
Description of the change
Adds a method to query the output configuration for a hwc display. With this MP the code path is not yet in use, but just prepared.
Kevin DuBois (kdub) wrote : | # |
52 + 25.4f * float(device.width) / float(device.xdpi),
53 + 25.4f * float(device.
magic numbers
873 +TEST_F(HWC10Tests, display_
847 +TEST_F(
introduction of new terminology with HWC10 and PostHWC10. In current code, hwc 1.0 is called HwcFbDevice, hwc 1.1+ is called HwcDevice.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2008
http://
Executed test runs:
FAILURE: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Alberto Aguirre (albaguirre) wrote : | # |
Is this being reworked based on kdub's feedback?
Or should we review as is?
Unmerged revisions
- 2008. By Andreas Pokorny
-
Add means to query display output configuration from DisplayDevice
This adds a methods to DisplayDevice and HwcWrapper to assemble a
DisplayConfigurationOutput using the fb and hwc interfaces and EGL.
The code is largely borrowed from mir::graphics::android: :Framebuffers.
This change does not yet make mir::android::DisplayConfigu ration use this
code path.
Preview Diff
1 | === modified file 'src/platform/graphics/android/CMakeLists.txt' |
2 | --- src/platform/graphics/android/CMakeLists.txt 2014-10-01 06:25:56 +0000 |
3 | +++ src/platform/graphics/android/CMakeLists.txt 2014-10-29 12:29:38 +0000 |
4 | @@ -14,6 +14,7 @@ |
5 | buffer.cpp |
6 | display.cpp |
7 | display_configuration.cpp |
8 | + display_configuration_utilities.cpp |
9 | display_buffer.cpp |
10 | output_builder.cpp |
11 | hwc_layerlist.cpp |
12 | |
13 | === added file 'src/platform/graphics/android/display_configuration_utilities.cpp' |
14 | --- src/platform/graphics/android/display_configuration_utilities.cpp 1970-01-01 00:00:00 +0000 |
15 | +++ src/platform/graphics/android/display_configuration_utilities.cpp 2014-10-29 12:29:38 +0000 |
16 | @@ -0,0 +1,57 @@ |
17 | +/* |
18 | + * Copyright © 2014 Canonical Ltd. |
19 | + * |
20 | + * This program is free software: you can redistribute it and/or modify it |
21 | + * under the terms of the GNU Lesser General Public License version 3, |
22 | + * as published by the Free Software Foundation. |
23 | + * |
24 | + * This program is distributed in the hope that it will be useful, |
25 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
26 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
27 | + * GNU Lesser General Public License for more details. |
28 | + * |
29 | + * You should have received a copy of the GNU Lesser General Public License |
30 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
31 | + * |
32 | + * Authored by: |
33 | + * Andreas Pokorny <andreas.pokorny@canonical.com> |
34 | + */ |
35 | + |
36 | +#include "display_configuration_utilities.h" |
37 | +#include "android_format_conversion-inl.h" |
38 | + |
39 | +#include "mir/graphics/display_configuration.h" |
40 | +#include "mir/geometry/point.h" |
41 | +#include "mir/geometry/size.h" |
42 | + |
43 | +#include <hardware/gralloc.h> |
44 | +#include <hardware/fb.h> |
45 | + |
46 | +namespace mg = mir::graphics; |
47 | +namespace mga = mg::android; |
48 | +namespace geom = mir::geometry; |
49 | +mg::DisplayConfigurationOutput mga::create_output_configuration_from_fb(framebuffer_device_t const& device) |
50 | +{ |
51 | + geometry::Size size_in_mm( |
52 | + 25.4f * float(device.width) / float(device.xdpi), |
53 | + 25.4f * float(device.height) / float(device.ydpi) |
54 | + ); |
55 | + |
56 | + return mg::DisplayConfigurationOutput |
57 | + { |
58 | + mg::DisplayConfigurationOutputId{0}, |
59 | + mg::DisplayConfigurationCardId{0}, |
60 | + mg::DisplayConfigurationOutputType::lvds, |
61 | + { mga::to_mir_format(device.format) }, // query for more? |
62 | + { {geom::Size{device.width, device.height}, double(device.fps)}}, |
63 | + 0, |
64 | + size_in_mm, |
65 | + true, |
66 | + true, |
67 | + geom::Point{0,0}, // top left |
68 | + 0, |
69 | + mga::to_mir_format(device.format), |
70 | + mir_power_mode_on, |
71 | + mir_orientation_normal |
72 | + }; |
73 | +} |
74 | |
75 | === added file 'src/platform/graphics/android/display_configuration_utilities.h' |
76 | --- src/platform/graphics/android/display_configuration_utilities.h 1970-01-01 00:00:00 +0000 |
77 | +++ src/platform/graphics/android/display_configuration_utilities.h 2014-10-29 12:29:38 +0000 |
78 | @@ -0,0 +1,35 @@ |
79 | +/* |
80 | + * Copyright © 2014 Canonical Ltd. |
81 | + * |
82 | + * This program is free software: you can redistribute it and/or modify it |
83 | + * under the terms of the GNU Lesser General Public License version 3, |
84 | + * as published by the Free Software Foundation. |
85 | + * |
86 | + * This program is distributed in the hope that it will be useful, |
87 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
88 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
89 | + * GNU Lesser General Public License for more details. |
90 | + * |
91 | + * You should have received a copy of the GNU Lesser General Public License |
92 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
93 | + * |
94 | + * Authored by: |
95 | + * Andreas Pokorny <andreas.pokorny@canonical.com> |
96 | + */ |
97 | + |
98 | +#ifndef MIR_GRAPHICS_ANDROID_DISPLAY_CONFIGURATION_UTILITIES_H_ |
99 | +#define MIR_GRAPHICS_ANDROID_DISPLAY_CONFIGURATION_UTILITIES_H_ |
100 | + |
101 | +struct framebuffer_device_t; |
102 | +namespace mir |
103 | +{ |
104 | +namespace graphics |
105 | +{ |
106 | +struct DisplayConfigurationOutput; |
107 | +namespace android |
108 | +{ |
109 | +DisplayConfigurationOutput create_output_configuration_from_fb(framebuffer_device_t const& device); |
110 | +} |
111 | +} |
112 | +} |
113 | +#endif /* MIR_GRAPHICS_ANDROID_DISPLAY_CONFIGURATION_UTILITIES_H_ */ |
114 | |
115 | === modified file 'src/platform/graphics/android/display_device.h' |
116 | --- src/platform/graphics/android/display_device.h 2014-10-01 06:25:56 +0000 |
117 | +++ src/platform/graphics/android/display_device.h 2014-10-29 12:29:38 +0000 |
118 | @@ -20,6 +20,7 @@ |
119 | #define MIR_GRAPHICS_ANDROID_DISPLAY_SUPPORT_PROVIDER_H_ |
120 | |
121 | #include "mir/graphics/renderable.h" |
122 | +#include "mir/graphics/display_configuration.h" |
123 | #include "mir_toolkit/common.h" |
124 | #include <EGL/egl.h> |
125 | |
126 | @@ -50,6 +51,7 @@ |
127 | RenderableList const& list, |
128 | RenderableListCompositor const& list_compositor) = 0; |
129 | virtual bool apply_orientation(MirOrientation orientation) const = 0; |
130 | + virtual DisplayConfigurationOutput get_output_configuration(DisplayConfigurationOutputId id) const = 0; |
131 | |
132 | protected: |
133 | DisplayDevice() = default; |
134 | |
135 | === modified file 'src/platform/graphics/android/fb_device.cpp' |
136 | --- src/platform/graphics/android/fb_device.cpp 2014-10-01 06:25:56 +0000 |
137 | +++ src/platform/graphics/android/fb_device.cpp 2014-10-29 12:29:38 +0000 |
138 | @@ -16,14 +16,18 @@ |
139 | * Authored by: Kevin DuBois <kevin.dubois@canonical.com> |
140 | */ |
141 | |
142 | +#include "fb_device.h" |
143 | +#include "swapping_gl_context.h" |
144 | +#include "framebuffer_bundle.h" |
145 | +#include "buffer.h" |
146 | +#include "display_configuration_utilities.h" |
147 | + |
148 | #include "mir/graphics/buffer.h" |
149 | #include "mir/graphics/android/native_buffer.h" |
150 | #include "mir/graphics/android/sync_fence.h" |
151 | -#include "swapping_gl_context.h" |
152 | -#include "android_format_conversion-inl.h" |
153 | -#include "fb_device.h" |
154 | -#include "framebuffer_bundle.h" |
155 | -#include "buffer.h" |
156 | + |
157 | +// usage of HWC_DISPLAY_PRIMARY to identify output attached to framebuffer: |
158 | +#include "hardware/hwcomposer_defs.h" |
159 | |
160 | #include <boost/throw_exception.hpp> |
161 | #include <stdexcept> |
162 | @@ -80,3 +84,12 @@ |
163 | fb_device->enableScreen(fb_device.get(), enable); |
164 | } |
165 | } |
166 | + |
167 | + |
168 | +mg::DisplayConfigurationOutput mga::FBDevice::get_output_configuration(mg::DisplayConfigurationOutputId id) const |
169 | +{ |
170 | + if (id.as_value() != HWC_DISPLAY_PRIMARY) |
171 | + BOOST_THROW_EXCEPTION(std::runtime_error("only primary display supported")); |
172 | + |
173 | + return mga::create_output_configuration_from_fb(*fb_device); |
174 | +} |
175 | |
176 | === modified file 'src/platform/graphics/android/fb_device.h' |
177 | --- src/platform/graphics/android/fb_device.h 2014-10-01 06:25:56 +0000 |
178 | +++ src/platform/graphics/android/fb_device.h 2014-10-29 12:29:38 +0000 |
179 | @@ -42,6 +42,7 @@ |
180 | SwappingGLContext const& context, |
181 | RenderableList const& list, |
182 | RenderableListCompositor const& list_compositor); |
183 | + DisplayConfigurationOutput get_output_configuration(DisplayConfigurationOutputId id) const override; |
184 | |
185 | private: |
186 | std::shared_ptr<framebuffer_device_t> const fb_device; |
187 | |
188 | === modified file 'src/platform/graphics/android/hwc_device.cpp' |
189 | --- src/platform/graphics/android/hwc_device.cpp 2014-10-01 06:25:56 +0000 |
190 | +++ src/platform/graphics/android/hwc_device.cpp 2014-10-29 12:29:38 +0000 |
191 | @@ -25,6 +25,15 @@ |
192 | #include "framebuffer_bundle.h" |
193 | #include "buffer.h" |
194 | #include "hwc_fallback_gl_renderer.h" |
195 | +#include "android_format_conversion-inl.h" |
196 | + |
197 | +#include "mir/geometry/size.h" |
198 | +#include "mir/geometry/point.h" |
199 | + |
200 | +#include <EGL/egl.h> |
201 | +#include <EGL/eglext.h> |
202 | + |
203 | +#include <boost/throw_exception.hpp> |
204 | #include <limits> |
205 | #include <algorithm> |
206 | |
207 | @@ -63,6 +72,59 @@ |
208 | } |
209 | return false; |
210 | } |
211 | + |
212 | +std::vector<MirPixelFormat> determine_hwc11_fb_formats() |
213 | +{ |
214 | + static EGLint const fb_egl_config_attr [] = |
215 | + { |
216 | + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, |
217 | + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, |
218 | + EGL_FRAMEBUFFER_TARGET_ANDROID, EGL_TRUE, |
219 | + EGL_NONE |
220 | + }; |
221 | + |
222 | + const EGLint config_size = 64; |
223 | + EGLConfig fb_egl_config[config_size]; |
224 | + int matching_configs; |
225 | + EGLint major, minor; |
226 | + auto egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY); |
227 | + eglInitialize(egl_display, &major, &minor); |
228 | + eglChooseConfig(egl_display, fb_egl_config_attr, fb_egl_config, config_size, &matching_configs); |
229 | + |
230 | + std::vector<MirPixelFormat> formats; |
231 | + std::transform(fb_egl_config, fb_egl_config+matching_configs, |
232 | + std::back_inserter(formats), |
233 | + [&](EGLConfig const& cfg) |
234 | + { |
235 | + int visual_id; |
236 | + eglGetConfigAttrib(egl_display, cfg, EGL_NATIVE_VISUAL_ID, &visual_id); |
237 | + return mga::to_mir_format(visual_id); |
238 | + } |
239 | + ); |
240 | + |
241 | + std::sort(begin(formats), end(formats)); |
242 | + formats.erase( |
243 | + std::unique( |
244 | + begin(formats), |
245 | + std::remove_if(begin(formats), end(formats), |
246 | + [](MirPixelFormat const& item ) |
247 | + { |
248 | + return item == mir_pixel_format_invalid; |
249 | + }) |
250 | + ), |
251 | + end(formats) |
252 | + ); |
253 | + |
254 | + if (formats.empty()) |
255 | + { |
256 | + //we couldn't figure out the fb format via egl. In this case, we |
257 | + //assume abgr_8888. HWC api really should provide this information directly. |
258 | + formats.push_back(mir_pixel_format_abgr_8888); |
259 | + } |
260 | + |
261 | + eglTerminate(egl_display); |
262 | + return formats; |
263 | +} |
264 | } |
265 | |
266 | mga::HwcDevice::HwcDevice(std::shared_ptr<HwcWrapper> const& hwc_wrapper, |
267 | @@ -194,3 +256,57 @@ |
268 | { |
269 | onscreen_overlay_buffers.clear(); |
270 | } |
271 | + |
272 | +mg::DisplayConfigurationOutput mga::HwcDevice::get_output_configuration(DisplayConfigurationOutputId id) const |
273 | +{ |
274 | + // TODO: only support primary for now, external is not allowed for now |
275 | + if (id.as_value() != HWC_DISPLAY_PRIMARY && |
276 | + id.as_value() != HWC_DISPLAY_EXTERNAL) |
277 | + BOOST_THROW_EXCEPTION(std::runtime_error("display not supported")); |
278 | + |
279 | + auto configs = hwc_wrapper->get_display_configs(id); |
280 | + |
281 | + if (configs.empty()) |
282 | + BOOST_THROW_EXCEPTION(std::runtime_error("No configs available for display")); |
283 | + |
284 | + std::vector<MirPixelFormat> formats{ determine_hwc11_fb_formats() }; |
285 | + MirPixelFormat current_format = formats[0]; |
286 | + |
287 | + std::vector<DisplayConfigurationMode> modes; |
288 | + geometry::Size output_size(0, 0); |
289 | + |
290 | + for(auto config : configs) |
291 | + { |
292 | + auto attributes = hwc_wrapper->get_display_config_attributes(id, config); |
293 | + modes.push_back(DisplayConfigurationMode{attributes.size, attributes.refresh_rate_hz}); |
294 | + geometry::Size size_in_mm( |
295 | + 25.4f * attributes.size.width.as_float() / float(attributes.dpi_x), |
296 | + 25.4f * attributes.size.height.as_float() / float(attributes.dpi_y) |
297 | + ); |
298 | + |
299 | + if (size_in_mm.width.as_int() * size_in_mm.height.as_int() > output_size.width.as_int() * output_size.height.as_int()) |
300 | + output_size = size_in_mm; |
301 | + } |
302 | + |
303 | + size_t preferred_mode_index = 0; |
304 | + |
305 | + return mg::DisplayConfigurationOutput |
306 | + { |
307 | + id, |
308 | + mg::DisplayConfigurationCardId{0}, |
309 | + id.as_value() == HWC_DISPLAY_PRIMARY? |
310 | + mg::DisplayConfigurationOutputType::lvds: |
311 | + mg::DisplayConfigurationOutputType::hdmia, |
312 | + std::move(formats), |
313 | + std::move(modes), |
314 | + preferred_mode_index, |
315 | + output_size, |
316 | + true, |
317 | + true, |
318 | + geometry::Point{0,0}, // top left |
319 | + 0, // current mode |
320 | + current_format, |
321 | + mir_power_mode_on, |
322 | + mir_orientation_normal |
323 | + }; |
324 | +} |
325 | |
326 | === modified file 'src/platform/graphics/android/hwc_device.h' |
327 | --- src/platform/graphics/android/hwc_device.h 2014-10-01 06:25:56 +0000 |
328 | +++ src/platform/graphics/android/hwc_device.h 2014-10-29 12:29:38 +0000 |
329 | @@ -50,6 +50,7 @@ |
330 | SwappingGLContext const& context, |
331 | RenderableList const& list, |
332 | RenderableListCompositor const& list_compositor); |
333 | + DisplayConfigurationOutput get_output_configuration(DisplayConfigurationOutputId id) const override; |
334 | |
335 | private: |
336 | bool buffer_is_onscreen(Buffer const&) const; |
337 | |
338 | === modified file 'src/platform/graphics/android/hwc_fb_device.cpp' |
339 | --- src/platform/graphics/android/hwc_fb_device.cpp 2014-10-01 06:25:56 +0000 |
340 | +++ src/platform/graphics/android/hwc_fb_device.cpp 2014-10-29 12:29:38 +0000 |
341 | @@ -21,6 +21,7 @@ |
342 | #include "hwc_vsync_coordinator.h" |
343 | #include "framebuffer_bundle.h" |
344 | #include "android_format_conversion-inl.h" |
345 | +#include "display_configuration_utilities.h" |
346 | #include "hwc_wrapper.h" |
347 | #include "hwc_fallback_gl_renderer.h" |
348 | #include "mir/graphics/buffer.h" |
349 | @@ -88,3 +89,11 @@ |
350 | { |
351 | return false; |
352 | } |
353 | + |
354 | +mg::DisplayConfigurationOutput mga::HwcFbDevice::get_output_configuration(mg::DisplayConfigurationOutputId id) const |
355 | +{ |
356 | + if (id.as_value() != HWC_DISPLAY_PRIMARY) |
357 | + BOOST_THROW_EXCEPTION(std::runtime_error("only primary display supported")); |
358 | + |
359 | + return mga::create_output_configuration_from_fb(*fb_device); |
360 | +} |
361 | |
362 | === modified file 'src/platform/graphics/android/hwc_fb_device.h' |
363 | --- src/platform/graphics/android/hwc_fb_device.h 2014-10-01 06:25:56 +0000 |
364 | +++ src/platform/graphics/android/hwc_fb_device.h 2014-10-29 12:29:38 +0000 |
365 | @@ -44,6 +44,7 @@ |
366 | SwappingGLContext const& context, |
367 | RenderableList const& list, |
368 | RenderableListCompositor const& list_compositor); |
369 | + DisplayConfigurationOutput get_output_configuration(DisplayConfigurationOutputId id) const override; |
370 | |
371 | private: |
372 | std::shared_ptr<HwcWrapper> const hwc_wrapper; |
373 | |
374 | === modified file 'src/platform/graphics/android/hwc_wrapper.h' |
375 | --- src/platform/graphics/android/hwc_wrapper.h 2014-10-01 06:25:56 +0000 |
376 | +++ src/platform/graphics/android/hwc_wrapper.h 2014-10-29 12:29:38 +0000 |
377 | @@ -19,6 +19,9 @@ |
378 | #ifndef MIR_GRAPHICS_ANDROID_HWC_WRAPPER_H_ |
379 | #define MIR_GRAPHICS_ANDROID_HWC_WRAPPER_H_ |
380 | |
381 | +#include "mir/graphics/display_configuration.h" |
382 | +#include "mir/geometry/size.h" |
383 | + |
384 | #include <hardware/hwcomposer.h> |
385 | #include <memory> |
386 | |
387 | @@ -42,6 +45,16 @@ |
388 | virtual void display_on() const = 0; |
389 | virtual void display_off() const = 0; |
390 | |
391 | + virtual std::vector<uint32_t> get_display_configs(DisplayConfigurationOutputId id) const = 0; |
392 | + struct Attributes |
393 | + { |
394 | + geometry::Size size; |
395 | + uint32_t dpi_x; |
396 | + uint32_t dpi_y; |
397 | + double refresh_rate_hz; |
398 | + }; |
399 | + virtual Attributes get_display_config_attributes(DisplayConfigurationOutputId id, uint32_t config) const = 0; |
400 | + |
401 | protected: |
402 | HwcWrapper() = default; |
403 | HwcWrapper& operator=(HwcWrapper const&) = delete; |
404 | |
405 | === modified file 'src/platform/graphics/android/real_hwc_wrapper.cpp' |
406 | --- src/platform/graphics/android/real_hwc_wrapper.cpp 2014-10-01 06:25:56 +0000 |
407 | +++ src/platform/graphics/android/real_hwc_wrapper.cpp 2014-10-29 12:29:38 +0000 |
408 | @@ -111,3 +111,48 @@ |
409 | } |
410 | logger->log_display_off(); |
411 | } |
412 | + |
413 | +std::vector<uint32_t> mga::RealHwcWrapper::get_display_configs(DisplayConfigurationOutputId id) const |
414 | +{ |
415 | + const int num_configs_to_query = 10; |
416 | + uint32_t query_results[num_configs_to_query]; |
417 | + size_t configs_received = num_configs_to_query; |
418 | + |
419 | + if (auto rc = hwc_device->getDisplayConfigs(hwc_device.get(), id.as_value(), query_results, &configs_received)) |
420 | + { |
421 | + std::stringstream ss; |
422 | + ss << "error querying display configs for display " << id.as_value() << ". rc = " << std::hex << rc; |
423 | + BOOST_THROW_EXCEPTION(std::runtime_error(ss.str())); |
424 | + } |
425 | + |
426 | + return {query_results, query_results + configs_received}; |
427 | +} |
428 | + |
429 | +mga::HwcWrapper::Attributes mga::RealHwcWrapper::get_display_config_attributes(DisplayConfigurationOutputId id, uint32_t config) const |
430 | +{ |
431 | + /* note: some drivers (qcom msm8960) choke if this is not the same size array |
432 | + as the one surfaceflinger submits */ |
433 | + static uint32_t const display_attribute_request[] = |
434 | + { |
435 | + HWC_DISPLAY_WIDTH, |
436 | + HWC_DISPLAY_HEIGHT, |
437 | + HWC_DISPLAY_VSYNC_PERIOD, |
438 | + HWC_DISPLAY_DPI_X, |
439 | + HWC_DISPLAY_DPI_Y, |
440 | + HWC_DISPLAY_NO_ATTRIBUTE, |
441 | + }; |
442 | + int32_t size_values[sizeof(display_attribute_request) / sizeof (display_attribute_request[0])] = {}; |
443 | + |
444 | + if (auto rc = hwc_device->getDisplayAttributes(hwc_device.get(), id.as_value(), config, |
445 | + display_attribute_request, size_values)) |
446 | + { |
447 | + std::stringstream ss; |
448 | + ss << "error querying attributes configs for display " << id.as_value() << ". rc = " << std::hex << rc; |
449 | + BOOST_THROW_EXCEPTION(std::runtime_error(ss.str())); |
450 | + } |
451 | + |
452 | + //HWC_DISPLAY_VSYNC_PERIOD is specified in nanoseconds |
453 | + double refresh_rate_hz = (size_values[2] > 0 ) ? 1000000000.0/size_values[2] : 0.0; |
454 | + return {{size_values[0], size_values[1]}, uint32_t(size_values[3]), uint32_t(size_values[4]), refresh_rate_hz}; |
455 | + } |
456 | + |
457 | |
458 | === modified file 'src/platform/graphics/android/real_hwc_wrapper.h' |
459 | --- src/platform/graphics/android/real_hwc_wrapper.h 2014-10-01 06:25:56 +0000 |
460 | +++ src/platform/graphics/android/real_hwc_wrapper.h 2014-10-29 12:29:38 +0000 |
461 | @@ -44,6 +44,8 @@ |
462 | void vsync_signal_off() const override; |
463 | void display_on() const override; |
464 | void display_off() const override; |
465 | + std::vector<uint32_t> get_display_configs(DisplayConfigurationOutputId id) const override; |
466 | + Attributes get_display_config_attributes(DisplayConfigurationOutputId id, uint32_t config) const override; |
467 | private: |
468 | static size_t const num_displays{3}; //primary, external, virtual |
469 | //note: the callbacks have to extend past the lifetime of the hwc_composer_device_1 for some |
470 | |
471 | === modified file 'tests/include/mir_test_doubles/mock_display_device.h' |
472 | --- tests/include/mir_test_doubles/mock_display_device.h 2014-10-01 06:25:56 +0000 |
473 | +++ tests/include/mir_test_doubles/mock_display_device.h 2014-10-29 12:29:38 +0000 |
474 | @@ -42,6 +42,7 @@ |
475 | graphics::RenderableList const&, |
476 | graphics::android::RenderableListCompositor const&)); |
477 | MOCK_CONST_METHOD1(apply_orientation, bool(MirOrientation)); |
478 | + MOCK_CONST_METHOD1(get_output_configuration, graphics::DisplayConfigurationOutput(graphics::DisplayConfigurationOutputId)); |
479 | }; |
480 | } |
481 | } |
482 | |
483 | === modified file 'tests/include/mir_test_doubles/mock_fb_hal_device.h' |
484 | --- tests/include/mir_test_doubles/mock_fb_hal_device.h 2014-03-06 06:05:17 +0000 |
485 | +++ tests/include/mir_test_doubles/mock_fb_hal_device.h 2014-10-29 12:29:38 +0000 |
486 | @@ -34,8 +34,8 @@ |
487 | class MockFBHalDevice : public framebuffer_device_t |
488 | { |
489 | public: |
490 | - MockFBHalDevice(unsigned int const width, unsigned int const height, |
491 | - int const pf, int const numfbs) |
492 | + MockFBHalDevice(unsigned int const width, unsigned int const height, int const pf, |
493 | + float const xdpi, float const ydpi, float const fps, int const numfbs) |
494 | : framebuffer_device_t({ |
495 | hw_device_t(), |
496 | 0, |
497 | @@ -43,9 +43,9 @@ |
498 | height, |
499 | 0, |
500 | pf, |
501 | - 0.0f, |
502 | - 0.0f, |
503 | - 0.0f, |
504 | + xdpi, |
505 | + ydpi, |
506 | + fps, |
507 | 0, |
508 | 1, |
509 | numfbs, |
510 | @@ -59,6 +59,12 @@ |
511 | enableScreen = hook_enableScreen; |
512 | } |
513 | |
514 | + MockFBHalDevice(unsigned int const width, unsigned int const height, |
515 | + int const pf, int const numfbs) |
516 | + : MockFBHalDevice(width, height, pf, 1.0f, 1.0f, 2.0f, numfbs) |
517 | + { |
518 | + } |
519 | + |
520 | MockFBHalDevice() |
521 | : MockFBHalDevice(1,1,1,1) |
522 | { |
523 | |
524 | === modified file 'tests/include/mir_test_doubles/mock_hwc_device_wrapper.h' |
525 | --- tests/include/mir_test_doubles/mock_hwc_device_wrapper.h 2014-10-01 06:25:56 +0000 |
526 | +++ tests/include/mir_test_doubles/mock_hwc_device_wrapper.h 2014-10-29 12:29:38 +0000 |
527 | @@ -39,6 +39,9 @@ |
528 | MOCK_CONST_METHOD0(vsync_signal_off, void()); |
529 | MOCK_CONST_METHOD0(display_on, void()); |
530 | MOCK_CONST_METHOD0(display_off, void()); |
531 | + MOCK_CONST_METHOD1(get_display_configs, std::vector<uint32_t>(graphics::DisplayConfigurationOutputId)); |
532 | + MOCK_CONST_METHOD2(get_display_config_attributes, Attributes(graphics::DisplayConfigurationOutputId, uint32_t)); |
533 | + |
534 | }; |
535 | |
536 | } |
537 | |
538 | === modified file 'tests/unit-tests/graphics/android/test_fb_device.cpp' |
539 | --- tests/unit-tests/graphics/android/test_fb_device.cpp 2014-10-01 06:25:56 +0000 |
540 | +++ tests/unit-tests/graphics/android/test_fb_device.cpp 2014-10-29 12:29:38 +0000 |
541 | @@ -47,10 +47,14 @@ |
542 | |
543 | width = 413; |
544 | height = 516; |
545 | + dpi_x = 96.0f; |
546 | + dpi_y = 96.0f; |
547 | + fps = 120.0f; |
548 | fbnum = 4; |
549 | format = HAL_PIXEL_FORMAT_RGBA_8888; |
550 | |
551 | - fb_hal_mock = std::make_shared<NiceMock<mtd::MockFBHalDevice>>(width, height, format, fbnum); |
552 | + fb_hal_mock = std::make_shared<NiceMock<mtd::MockFBHalDevice>>(width, height, format, |
553 | + dpi_x, dpi_y, fps, fbnum); |
554 | mock_buffer = std::make_shared<NiceMock<mtd::MockBuffer>>(); |
555 | native_buffer = std::make_shared<mtd::StubAndroidNativeBuffer>(); |
556 | ON_CALL(*mock_buffer, native_buffer_handle()) |
557 | @@ -60,6 +64,7 @@ |
558 | } |
559 | |
560 | unsigned int width, height, format, fbnum; |
561 | + float dpi_x, dpi_y, fps; |
562 | std::shared_ptr<mtd::MockFBHalDevice> fb_hal_mock; |
563 | std::shared_ptr<mtd::MockBuffer> mock_buffer; |
564 | std::shared_ptr<mir::graphics::NativeBuffer> native_buffer; |
565 | @@ -140,3 +145,43 @@ |
566 | fbdev.mode(mir_power_mode_off); |
567 | fbdev.mode(mir_power_mode_on); |
568 | } |
569 | + |
570 | +TEST_F(FBDevice, throws_on_wrong_display_id) |
571 | +{ |
572 | + mga::FBDevice fbdev(fb_hal_mock); |
573 | + EXPECT_THROW( |
574 | + {fbdev.get_output_configuration(mg::DisplayConfigurationOutputId{HWC_DISPLAY_VIRTUAL});}, |
575 | + std::runtime_error); |
576 | + EXPECT_THROW( |
577 | + {fbdev.get_output_configuration(mg::DisplayConfigurationOutputId{HWC_DISPLAY_EXTERNAL});}, |
578 | + std::runtime_error); |
579 | + EXPECT_NO_THROW( |
580 | + {fbdev.get_output_configuration(mg::DisplayConfigurationOutputId{HWC_DISPLAY_PRIMARY});}); |
581 | +} |
582 | + |
583 | +TEST_F(FBDevice, display_output_configuration_matches) |
584 | +{ |
585 | + using namespace testing; |
586 | + mga::FBDevice fbdev(fb_hal_mock); |
587 | + EXPECT_THAT( |
588 | + fbdev.get_output_configuration(mg::DisplayConfigurationOutputId{HWC_DISPLAY_PRIMARY}), |
589 | + Eq( |
590 | + mg::DisplayConfigurationOutput |
591 | + { |
592 | + mg::DisplayConfigurationOutputId{HWC_DISPLAY_PRIMARY}, |
593 | + mg::DisplayConfigurationCardId{0}, |
594 | + mg::DisplayConfigurationOutputType::lvds, |
595 | + {mir_pixel_format_argb_8888}, |
596 | + {{{413, 516}, 120.0f}}, |
597 | + 0, |
598 | + {109, 136}, |
599 | + true, |
600 | + true, |
601 | + {0, 0}, |
602 | + 0, |
603 | + mir_pixel_format_abgr_8888, |
604 | + mir_power_mode_on, |
605 | + mir_orientation_normal |
606 | + } |
607 | + )); |
608 | +} |
609 | |
610 | === modified file 'tests/unit-tests/graphics/android/test_hwc_common_device.cpp' |
611 | --- tests/unit-tests/graphics/android/test_hwc_common_device.cpp 2014-10-01 06:25:56 +0000 |
612 | +++ tests/unit-tests/graphics/android/test_hwc_common_device.cpp 2014-10-29 12:29:38 +0000 |
613 | @@ -36,7 +36,8 @@ |
614 | #include <memory> |
615 | #include <gtest/gtest.h> |
616 | |
617 | -namespace mga=mir::graphics::android; |
618 | +namespace mg=mir::graphics; |
619 | +namespace mga=mg::android; |
620 | namespace mtd=mir::test::doubles; |
621 | namespace geom=mir::geometry; |
622 | |
623 | @@ -65,28 +66,90 @@ |
624 | return std::make_shared<mga::HwcDevice>(hwc_device, coordinator, file_ops); |
625 | } |
626 | |
627 | -template<typename T> |
628 | -class HWCCommon : public ::testing::Test |
629 | +class HWCCommonFixture : public ::testing::Test |
630 | { |
631 | protected: |
632 | - virtual void SetUp() |
633 | + void setup_display_config() |
634 | + { |
635 | + ON_CALL(*this->mock_device, get_display_configs(primary)) |
636 | + .WillByDefault(testing::Return(std::vector<uint32_t>{0})); |
637 | + |
638 | + ON_CALL(*this->mock_device, get_display_configs(external)) |
639 | + .WillByDefault(testing::Return(std::vector<uint32_t>{1})); |
640 | + |
641 | + ON_CALL(*this->mock_device, get_display_config_attributes(primary, 0)) |
642 | + .WillByDefault(testing::Return( |
643 | + mga::HwcWrapper::Attributes{ |
644 | + geom::Size{280,190}, |
645 | + 320, // dpi x |
646 | + 320, // dpi y |
647 | + 60 // hz |
648 | + })); |
649 | + |
650 | + ON_CALL(*this->mock_device, get_display_config_attributes(external, 1)) |
651 | + .WillByDefault(testing::Return( |
652 | + mga::HwcWrapper::Attributes{ |
653 | + geom::Size{1920,1200}, |
654 | + 120, // dpi x |
655 | + 120, // dpi y |
656 | + 60 // hz |
657 | + })); |
658 | + } |
659 | + void setup_egl_configs() |
660 | { |
661 | using namespace testing; |
662 | - |
663 | - mock_fbdev = std::make_shared<mtd::MockFBHalDevice>(); |
664 | - mock_device = std::make_shared<testing::NiceMock<mtd::MockHWCDeviceWrapper>>(); |
665 | - mock_vsync = std::make_shared<testing::NiceMock<mtd::MockVsyncCoordinator>>(); |
666 | + ON_CALL(mock_egl,eglChooseConfig(_,_,_,_,_)) |
667 | + .WillByDefault( |
668 | + Invoke([](EGLDisplay, EGLint const *, EGLConfig * configs, EGLint config_size, EGLint * num_config) |
669 | + { |
670 | + if (config_size >= 3) |
671 | + configs[1] = EGLConfig(42); |
672 | + if (config_size >= 2) |
673 | + configs[1] = EGLConfig(13); |
674 | + if (config_size >= 1) |
675 | + configs[0] = EGLConfig(21); |
676 | + *num_config = std::min(3,config_size); |
677 | + return EGL_TRUE; |
678 | + }) |
679 | + ); |
680 | + |
681 | + ON_CALL(mock_egl,eglGetConfigAttrib(_,_,_,_)) |
682 | + .WillByDefault( |
683 | + Invoke([](EGLDisplay, EGLConfig config, EGLint attribute, EGLint * value) -> EGLBoolean |
684 | + { |
685 | + if (!value) return EGL_FALSE; |
686 | + if (attribute!=EGL_NATIVE_VISUAL_ID) return EGL_FALSE; |
687 | + |
688 | + if (config == EGLConfig(42)) |
689 | + *value = 0; // place holder for format that cannot be converted to mir format |
690 | + if (config == EGLConfig(13)) |
691 | + *value = HAL_PIXEL_FORMAT_RGBA_8888; |
692 | + if (config == EGLConfig(21)) |
693 | + *value = HAL_PIXEL_FORMAT_RGBX_8888; |
694 | + return EGL_TRUE; |
695 | + }) |
696 | + ); |
697 | } |
698 | - |
699 | testing::NiceMock<mtd::MockEGL> mock_egl; |
700 | - std::shared_ptr<mtd::MockVsyncCoordinator> mock_vsync; |
701 | - std::shared_ptr<mtd::MockHWCDeviceWrapper> mock_device; |
702 | - std::shared_ptr<mtd::MockFBHalDevice> mock_fbdev; |
703 | + std::shared_ptr<mtd::MockVsyncCoordinator> mock_vsync = std::make_shared<testing::NiceMock<mtd::MockVsyncCoordinator>>(); |
704 | + std::shared_ptr<mtd::MockHWCDeviceWrapper> mock_device = std::make_shared<testing::NiceMock<mtd::MockHWCDeviceWrapper>>(); |
705 | + std::shared_ptr<mtd::MockFBHalDevice> mock_fbdev = std::make_shared<mtd::MockFBHalDevice>(900, 600, HAL_PIXEL_FORMAT_RGBX_8888, |
706 | + 400.0f, 400.0f, 67.6f, 1); |
707 | + |
708 | + mg::DisplayConfigurationOutputId primary{HWC_DISPLAY_PRIMARY}; |
709 | + mg::DisplayConfigurationOutputId external{HWC_DISPLAY_EXTERNAL}; |
710 | + mg::DisplayConfigurationOutputId virtual_output{HWC_DISPLAY_VIRTUAL}; |
711 | }; |
712 | |
713 | +template<typename T> |
714 | +using HWCCommon = HWCCommonFixture; |
715 | + |
716 | typedef ::testing::Types<mga::HwcFbDevice, mga::HwcDevice> HWCDeviceTestTypes; |
717 | TYPED_TEST_CASE(HWCCommon, HWCDeviceTestTypes); |
718 | |
719 | +using PostHWC10Tests = HWCCommonFixture; |
720 | +using HWC10Tests = HWCCommonFixture; |
721 | + |
722 | TYPED_TEST(HWCCommon, test_proc_registration) |
723 | { |
724 | using namespace testing; |
725 | @@ -228,3 +291,174 @@ |
726 | auto device = make_hwc_device<TypeParam>(this->mock_device, this->mock_fbdev, this->mock_vsync); |
727 | }); |
728 | } |
729 | + |
730 | +TEST_F(HWC10Tests, throws_on_non_primary_display_output_configurations) |
731 | +{ |
732 | + using namespace testing; |
733 | + auto device = make_hwc_device<mga::HwcFbDevice>(this->mock_device, this->mock_fbdev, this->mock_vsync); |
734 | + |
735 | + EXPECT_THROW({ |
736 | + device->get_output_configuration(this->external); |
737 | + }, std::runtime_error); |
738 | + EXPECT_THROW({ |
739 | + device->get_output_configuration(this->virtual_output); |
740 | + }, std::runtime_error); |
741 | +} |
742 | + |
743 | +TEST_F(PostHWC10Tests, throws_on_virtual_display_output_configurations) |
744 | +{ |
745 | + using namespace testing; |
746 | + this->setup_display_config(); |
747 | + auto device = make_hwc_device<mga::HwcDevice>(this->mock_device, this->mock_fbdev, this->mock_vsync); |
748 | + |
749 | + EXPECT_THROW({device->get_output_configuration(this->virtual_output);}, std::runtime_error); |
750 | + EXPECT_NO_THROW({device->get_output_configuration(this->external);}); |
751 | + EXPECT_NO_THROW({device->get_output_configuration(this->primary);}); |
752 | +} |
753 | + |
754 | +TEST_F(PostHWC10Tests, queries_hwc_device_for_configs) |
755 | +{ |
756 | + using namespace testing; |
757 | + this->setup_display_config(); |
758 | + |
759 | + auto device = make_hwc_device<mga::HwcDevice>(this->mock_device, this->mock_fbdev, this->mock_vsync); |
760 | + |
761 | + EXPECT_CALL(*this->mock_device, get_display_configs(this->primary)); |
762 | + |
763 | + device->get_output_configuration(this->primary); |
764 | +} |
765 | + |
766 | +TEST_F(PostHWC10Tests, throws_on_no_available_hwc_configurations) |
767 | +{ |
768 | + using namespace testing; |
769 | + auto device = make_hwc_device<mga::HwcDevice>(this->mock_device, this->mock_fbdev, this->mock_vsync); |
770 | + |
771 | + ON_CALL(*this->mock_device, get_display_configs(_)) |
772 | + .WillByDefault(Return(std::vector<uint32_t>{})); |
773 | + EXPECT_THROW({ |
774 | + device->get_output_configuration(this->primary); |
775 | + }, std::runtime_error); |
776 | +} |
777 | + |
778 | +TEST_F(PostHWC10Tests, queries_display_config_attributes) |
779 | +{ |
780 | + using namespace testing; |
781 | + this->setup_display_config(); |
782 | + auto device = make_hwc_device<mga::HwcDevice>(this->mock_device, this->mock_fbdev, this->mock_vsync); |
783 | + |
784 | + EXPECT_CALL(*this->mock_device, get_display_config_attributes(this->primary, 0)); |
785 | + |
786 | + device->get_output_configuration(this->primary); |
787 | +} |
788 | + |
789 | +TEST_F(PostHWC10Tests, display_configuration_matches_expectations) |
790 | +{ |
791 | + using namespace testing; |
792 | + this->setup_display_config(); |
793 | + auto device = make_hwc_device<mga::HwcDevice>(this->mock_device, this->mock_fbdev, this->mock_vsync); |
794 | + |
795 | + EXPECT_THAT( |
796 | + device->get_output_configuration(this->primary), |
797 | + Eq( |
798 | + mg::DisplayConfigurationOutput |
799 | + { |
800 | + this->primary, |
801 | + mg::DisplayConfigurationCardId{0}, |
802 | + mg::DisplayConfigurationOutputType::lvds, |
803 | + {mir_pixel_format_abgr_8888}, |
804 | + {{{280, 190}, 60}}, |
805 | + 0, |
806 | + {22, 15}, |
807 | + true, |
808 | + true, |
809 | + {0, 0}, |
810 | + 0, |
811 | + mir_pixel_format_abgr_8888, |
812 | + mir_power_mode_on, |
813 | + mir_orientation_normal |
814 | + } |
815 | + )); |
816 | +} |
817 | + |
818 | +TEST_F(PostHWC10Tests, display_configuration_matches_expectations_on_external_display) |
819 | +{ |
820 | + using namespace testing; |
821 | + this->setup_display_config(); |
822 | + auto device = make_hwc_device<mga::HwcDevice>(this->mock_device, this->mock_fbdev, this->mock_vsync); |
823 | + |
824 | + EXPECT_THAT( |
825 | + device->get_output_configuration(this->external), |
826 | + Eq( |
827 | + mg::DisplayConfigurationOutput |
828 | + { |
829 | + this->external, |
830 | + mg::DisplayConfigurationCardId{0}, |
831 | + mg::DisplayConfigurationOutputType::hdmia, |
832 | + {mir_pixel_format_abgr_8888}, |
833 | + {{{1920, 1200}, 60}}, |
834 | + 0, |
835 | + {406, 254}, |
836 | + true, |
837 | + true, |
838 | + {0, 0}, |
839 | + 0, |
840 | + mir_pixel_format_abgr_8888, |
841 | + mir_power_mode_on, |
842 | + mir_orientation_normal |
843 | + } |
844 | + )); |
845 | +} |
846 | + |
847 | +TEST_F(PostHWC10Tests, queries_egl_configuration) |
848 | +{ |
849 | + using namespace testing; |
850 | + this->setup_display_config(); |
851 | + this->setup_egl_configs(); |
852 | + auto device = make_hwc_device<mga::HwcDevice>(this->mock_device, this->mock_fbdev, this->mock_vsync); |
853 | + |
854 | + EXPECT_CALL(mock_egl,eglChooseConfig(_,_,_,_,_)).Times(1); |
855 | + EXPECT_CALL(mock_egl,eglGetConfigAttrib(_,_,EGL_NATIVE_VISUAL_ID,_)).Times(3); |
856 | + |
857 | + device->get_output_configuration(this->primary); |
858 | +} |
859 | + |
860 | +TEST_F(PostHWC10Tests, converts_egl_configs_to_mir_pixel_formats) |
861 | +{ |
862 | + using namespace testing; |
863 | + this->setup_display_config(); |
864 | + this->setup_egl_configs(); |
865 | + auto device = make_hwc_device<mga::HwcDevice>(this->mock_device, this->mock_fbdev, this->mock_vsync); |
866 | + |
867 | + EXPECT_THAT( |
868 | + device->get_output_configuration(this->primary).pixel_formats, |
869 | + Eq(std::vector<MirPixelFormat>({mir_pixel_format_abgr_8888, mir_pixel_format_xbgr_8888})) |
870 | + ); |
871 | +} |
872 | + |
873 | +TEST_F(HWC10Tests, display_configuration_matches_expectations) |
874 | +{ |
875 | + using namespace testing; |
876 | + auto device = make_hwc_device<mga::HwcFbDevice>(this->mock_device, this->mock_fbdev, this->mock_vsync); |
877 | + |
878 | + EXPECT_THAT( |
879 | + device->get_output_configuration(this->primary), |
880 | + Eq( |
881 | + mg::DisplayConfigurationOutput |
882 | + { |
883 | + this->primary, |
884 | + mg::DisplayConfigurationCardId{0}, |
885 | + mg::DisplayConfigurationOutputType::lvds, |
886 | + {mir_pixel_format_xbgr_8888}, |
887 | + {{{900, 600}, 67.6f}}, |
888 | + 0, |
889 | + {57, 38}, |
890 | + true, |
891 | + true, |
892 | + {0, 0}, |
893 | + 0, |
894 | + mir_pixel_format_xbgr_8888, |
895 | + mir_power_mode_on, |
896 | + mir_orientation_normal |
897 | + }) |
898 | + ); |
899 | +} |
407 +++ src/platform/ graphics/ android/ real_hwc_ wrapper. cpp
This is supposed to be an adapter layer around the hwc interface. Its kept thin and mostly in terms of hwc types so that the logs can closely reflect the actual calls to the 3rd party code. This lets us collaborate more easily with vendors. It shouldn't be doing heavy lifting. The code that was added is a duplication of the code in framebuffers.cpp
77 +++ src/platform/ graphics/ android/ display_ configuration_ utilities. h
given this would only be used by the fb device, it would probably be better to be in an anonymous namespace closer to the creation of the the fb_device.cpp file instead of in the two types of DisplayDevices that rely on the framebuffer device.
200 +#include <EGL/egl.h>
201 +#include <EGL/eglext.h>
I've gone through some pains to keep egl out of the displaydevice setup, would like to keep the egl stuff in the DisplayBuffer or the HwcFallbackRenderer
290 + for(auto config : configs)
const&