Merge lp:~alan-griffiths/mir/mesa-hybrid-cursor into lp:mir
- mesa-hybrid-cursor
- Merge into development-branch
Status: | Merged |
---|---|
Approved by: | Alan Griffiths |
Approved revision: | no longer in the source branch. |
Merged at revision: | 4193 |
Proposed branch: | lp:~alan-griffiths/mir/mesa-hybrid-cursor |
Merge into: | lp:mir |
Diff against target: |
547 lines (+259/-63) 7 files modified
src/common/CMakeLists.txt (+2/-1) src/platforms/mesa/server/kms/CMakeLists.txt (+1/-0) src/platforms/mesa/server/kms/cursor.cpp (+117/-31) src/platforms/mesa/server/kms/cursor.h (+21/-7) src/platforms/mesa/server/kms/display.cpp (+3/-14) src/platforms/mesa/server/kms/mutex.h (+104/-0) tests/unit-tests/platforms/mesa/kms/test_cursor.cpp (+11/-10) |
To merge this branch: | bzr merge lp:~alan-griffiths/mir/mesa-hybrid-cursor |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Mir CI Bot | continuous-integration | Approve | |
Chris Halse Rogers | Approve | ||
Alberto Aguirre (community) | Approve | ||
Alan Griffiths | Pending | ||
Review via email: mp+325215@code.launchpad.net |
This proposal supersedes a proposal from 2017-03-22.
Commit message
mesa-kms: Support hardware cursors in hybrid setups.
Description of the change
Mir CI Bot (mir-ci-bot) wrote : Posted in a previous version of this proposal | # |
Mir CI Bot (mir-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:4087
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
Mir CI Bot (mir-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:4087
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
Mir CI Bot (mir-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:4088
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
Mir CI Bot (mir-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:4088
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal | # |
It isn't clear why this failed CI (and too much time has passed to see any logs).
It still merges and doesn't obviously break things - so is it still worth landing?
Mir CI Bot (mir-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:4088
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
Chris Halse Rogers (raof) wrote : Posted in a previous version of this proposal | # |
It's still worth merging. Once it builds, it seems!
Mir CI Bot (mir-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:4191
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Alberto Aguirre (albaguirre) wrote : | # |
+{
87 + const_cast<
88 + const_cast<
Seems like undefined behavior.
Use a unique_ptr with custom deleter instead and move the unique_ptrs on move constructor.
165 + memset(dest, 0, buffer_stride * (gbm_bo_
"gbm_bo_
Alan Griffiths (alan-griffiths) wrote : | # |
> +{
> 87 + const_cast<
> 88 + const_cast<
>
> Seems like undefined behavior.
Fixed
> 165 + memset(dest, 0, buffer_stride * (gbm_bo_
> image_height));
>
> "gbm_bo_
> converted to size_t (so a huge number - Needs a check.
Unless I'm missing something (always possible) there is a check Vis:
if (image_width > min_buffer_width || image_height > min_buffer_height)
{
}
AIUI min_buffer_height ought to be <= gbm_bo_
Mir CI Bot (mir-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:4192
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Alberto Aguirre (albaguirre) wrote : | # |
Oh right... it was just a convoluted way of checking yeah.
Mir CI Bot (mir-ci-bot) : | # |
Mir CI Bot (mir-ci-bot) wrote : | # |
FAILED: Autolanding.
More details in the following jenkins job:
https:/
Executed test runs:
SUCCESS: https:/
FAILURE: https:/
None: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Chris Halse Rogers (raof) wrote : | # |
LGTM.
FWIW, this seems to be against our style guide:
191 + {
192 + pad_and_
193 + } else
194 + {
Mir CI Bot (mir-ci-bot) : | # |
Mir CI Bot (mir-ci-bot) wrote : | # |
FAILED: Autolanding.
Unapproved changes made after approval.
https:/
Executed test runs:
SUCCESS: https:/
None: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Mir CI Bot (mir-ci-bot) wrote : | # |
FAILED: Autolanding.
More details in the following jenkins job:
https:/
Executed test runs:
SUCCESS: https:/
FAILURE: https:/
None: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Mir CI Bot (mir-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:4193
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Mir CI Bot (mir-ci-bot) : | # |
Preview Diff
1 | === modified file 'src/common/CMakeLists.txt' |
2 | --- src/common/CMakeLists.txt 2017-05-08 03:04:26 +0000 |
3 | +++ src/common/CMakeLists.txt 2017-06-09 10:22:51 +0000 |
4 | @@ -20,7 +20,8 @@ |
5 | $<TARGET_OBJECTS:mirtime> |
6 | ${CMAKE_CURRENT_SOURCE_DIR}/output_type_names.cpp |
7 | ${CMAKE_CURRENT_SOURCE_DIR}/log.cpp |
8 | - ${CMAKE_CURRENT_SOURCE_DIR}/libname.cpp ${PROJECT_SOURCE_DIR}/include/common/mir/libname.h |
9 | + ${CMAKE_CURRENT_SOURCE_DIR}/libname.cpp |
10 | + ${PROJECT_SOURCE_DIR}/include/common/mir/libname.h |
11 | ${PROJECT_SOURCE_DIR}/include/common/mir/posix_rw_mutex.h |
12 | posix_rw_mutex.cpp |
13 | edid.cpp |
14 | |
15 | === modified file 'src/platforms/mesa/server/kms/CMakeLists.txt' |
16 | --- src/platforms/mesa/server/kms/CMakeLists.txt 2017-05-17 04:48:46 +0000 |
17 | +++ src/platforms/mesa/server/kms/CMakeLists.txt 2017-06-09 10:22:51 +0000 |
18 | @@ -43,6 +43,7 @@ |
19 | real_kms_output_container.cpp |
20 | egl_helper.h |
21 | egl_helper.cpp |
22 | + mutex.h |
23 | ) |
24 | |
25 | configure_file(${CMAKE_CURRENT_SOURCE_DIR}/symbols.map.in |
26 | |
27 | === modified file 'src/platforms/mesa/server/kms/cursor.cpp' |
28 | --- src/platforms/mesa/server/kms/cursor.cpp 2017-05-08 03:04:26 +0000 |
29 | +++ src/platforms/mesa/server/kms/cursor.cpp 2017-06-09 10:22:51 +0000 |
30 | @@ -88,34 +88,74 @@ |
31 | drmGetCap(fd, DRM_CAP_CURSOR_WIDTH, &width); |
32 | return int(width); |
33 | } |
34 | -} |
35 | - |
36 | -mgm::Cursor::GBMBOWrapper::GBMBOWrapper(gbm_device* gbm) : |
37 | - buffer(gbm_bo_create( |
38 | - gbm, |
39 | - get_drm_cursor_width(gbm_device_get_fd(gbm)), |
40 | - get_drm_cursor_height(gbm_device_get_fd(gbm)), |
41 | - GBM_FORMAT_ARGB8888, |
42 | - GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE)) |
43 | + |
44 | +gbm_device* gbm_create_device_checked(int fd) |
45 | +{ |
46 | + auto device = gbm_create_device(fd); |
47 | + if (!device) |
48 | + { |
49 | + BOOST_THROW_EXCEPTION(std::runtime_error("Failed to create gbm device")); |
50 | + } |
51 | + return device; |
52 | +} |
53 | +} |
54 | + |
55 | +mgm::Cursor::GBMBOWrapper::GBMBOWrapper(int fd) : |
56 | + device{gbm_create_device_checked(fd)}, |
57 | + buffer{ |
58 | + gbm_bo_create( |
59 | + device, |
60 | + get_drm_cursor_width(fd), |
61 | + get_drm_cursor_height(fd), |
62 | + GBM_FORMAT_ARGB8888, |
63 | + GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE)} |
64 | { |
65 | if (!buffer) BOOST_THROW_EXCEPTION(std::runtime_error("failed to create gbm buffer")); |
66 | } |
67 | |
68 | -inline mgm::Cursor::GBMBOWrapper::operator gbm_bo*() { return buffer; } |
69 | -inline mgm::Cursor::GBMBOWrapper::~GBMBOWrapper() { gbm_bo_destroy(buffer); } |
70 | +inline mgm::Cursor::GBMBOWrapper::operator gbm_bo*() |
71 | +{ |
72 | + return buffer; |
73 | +} |
74 | + |
75 | +inline mgm::Cursor::GBMBOWrapper::~GBMBOWrapper() |
76 | +{ |
77 | + if (device) |
78 | + gbm_device_destroy(device); |
79 | + if (buffer) |
80 | + gbm_bo_destroy(buffer); |
81 | +} |
82 | + |
83 | +mgm::Cursor::GBMBOWrapper::GBMBOWrapper(GBMBOWrapper&& from) |
84 | + : device{from.device}, |
85 | + buffer{from.buffer} |
86 | +{ |
87 | + from.buffer = nullptr; |
88 | + from.device = nullptr; |
89 | +} |
90 | |
91 | mgm::Cursor::Cursor( |
92 | - gbm_device* gbm, |
93 | KMSOutputContainer& output_container, |
94 | std::shared_ptr<CurrentConfiguration> const& current_configuration) : |
95 | output_container(output_container), |
96 | current_position(), |
97 | last_set_failed(false), |
98 | - buffer(gbm), |
99 | - buffer_width(gbm_bo_get_width(buffer)), |
100 | - buffer_height(gbm_bo_get_height(buffer)), |
101 | + min_buffer_width{std::numeric_limits<uint32_t>::max()}, |
102 | + min_buffer_height{std::numeric_limits<uint32_t>::max()}, |
103 | current_configuration(current_configuration) |
104 | { |
105 | + // Generate the buffers for the initial configuration. |
106 | + current_configuration->with_current_configuration_do( |
107 | + [this](KMSDisplayConfiguration const& kms_conf) |
108 | + { |
109 | + kms_conf.for_each_output( |
110 | + [this, &kms_conf](auto const& output) |
111 | + { |
112 | + // I'm not sure why g++ needs the explicit "this->" but it does - alan_g |
113 | + this->buffer_for_output(*kms_conf.get_output_for(output.id)); |
114 | + }); |
115 | + }); |
116 | + |
117 | hide(); |
118 | if (last_set_failed) |
119 | throw std::runtime_error("Initial KMS cursor set failed"); |
120 | @@ -126,7 +166,11 @@ |
121 | hide(); |
122 | } |
123 | |
124 | -void mgm::Cursor::write_buffer_data_locked(std::lock_guard<std::mutex> const&, void const* data, size_t count) |
125 | +void mgm::Cursor::write_buffer_data_locked( |
126 | + std::lock_guard<std::mutex> const&, |
127 | + gbm_bo* buffer, |
128 | + void const* data, |
129 | + size_t count) |
130 | { |
131 | if (auto result = gbm_bo_write(buffer, data, count)) |
132 | { |
133 | @@ -136,20 +180,23 @@ |
134 | } |
135 | } |
136 | |
137 | -void mgm::Cursor::pad_and_write_image_data_locked(std::lock_guard<std::mutex> const& lg, CursorImage const& image) |
138 | +void mgm::Cursor::pad_and_write_image_data_locked( |
139 | + std::lock_guard<std::mutex> const& lg, |
140 | + gbm_bo* buffer, |
141 | + CursorImage const& image) |
142 | { |
143 | auto image_argb = static_cast<uint8_t const*>(image.as_argb_8888()); |
144 | auto image_width = image.size().width.as_uint32_t(); |
145 | auto image_height = image.size().height.as_uint32_t(); |
146 | auto image_stride = image_width * 4; |
147 | |
148 | - if (image_width > buffer_width || image_height > buffer_height) |
149 | + if (image_width > min_buffer_width || image_height > min_buffer_height) |
150 | { |
151 | BOOST_THROW_EXCEPTION(std::logic_error("Image is too big for GBM cursor buffer")); |
152 | } |
153 | - |
154 | + |
155 | size_t buffer_stride = gbm_bo_get_stride(buffer); // in bytes |
156 | - size_t padded_size = buffer_stride * buffer_height; |
157 | + size_t padded_size = buffer_stride * gbm_bo_get_height(buffer); |
158 | auto padded = std::unique_ptr<uint8_t[]>(new uint8_t[padded_size]); |
159 | size_t rhs_padding = buffer_stride - image_stride; |
160 | |
161 | @@ -164,9 +211,9 @@ |
162 | src += image_stride; |
163 | } |
164 | |
165 | - memset(dest, 0, buffer_stride * (buffer_height - image_height)); |
166 | + memset(dest, 0, buffer_stride * (gbm_bo_get_height(buffer) - image_height)); |
167 | |
168 | - write_buffer_data_locked(lg, &padded[0], padded_size); |
169 | + write_buffer_data_locked(lg, buffer, &padded[0], padded_size); |
170 | } |
171 | |
172 | void mgm::Cursor::show() |
173 | @@ -186,14 +233,21 @@ |
174 | |
175 | auto const& size = cursor_image.size(); |
176 | |
177 | - if (size != geometry::Size{buffer_width, buffer_height}) |
178 | - { |
179 | - pad_and_write_image_data_locked(lg, cursor_image); |
180 | - } |
181 | - else |
182 | - { |
183 | - auto const count = size.width.as_uint32_t() * size.height.as_uint32_t() * sizeof(uint32_t); |
184 | - write_buffer_data_locked(lg, cursor_image.as_argb_8888(), count); |
185 | + { |
186 | + auto locked_buffers = buffers.lock(); |
187 | + for (auto& pair : *locked_buffers) |
188 | + { |
189 | + auto& buffer = pair.second; |
190 | + if (size != geometry::Size{gbm_bo_get_width(buffer), gbm_bo_get_height(buffer)}) |
191 | + { |
192 | + pad_and_write_image_data_locked(lg, buffer, cursor_image); |
193 | + } |
194 | + else |
195 | + { |
196 | + auto const count = size.width.as_uint32_t() * size.height.as_uint32_t() * sizeof(uint32_t); |
197 | + write_buffer_data_locked(lg, buffer, cursor_image.as_argb_8888(), count); |
198 | + } |
199 | + } |
200 | } |
201 | hotspot = cursor_image.hotspot(); |
202 | |
203 | @@ -288,7 +342,7 @@ |
204 | output.move_cursor(geom::Point{} + dp - hotspot); |
205 | if (force_state || !output.has_cursor()) // TODO - or if orientation had changed - then set buffer.. |
206 | { |
207 | - if (!output.set_cursor(buffer) || !output.has_cursor()) |
208 | + if (!output.set_cursor(buffer_for_output(output)) || !output.has_cursor()) |
209 | set_on_all_outputs = false; |
210 | } |
211 | } |
212 | @@ -303,3 +357,35 @@ |
213 | |
214 | last_set_failed = !set_on_all_outputs; |
215 | } |
216 | + |
217 | +gbm_bo* mgm::Cursor::buffer_for_output(KMSOutput const& output) |
218 | +{ |
219 | + auto locked_buffers = buffers.lock(); |
220 | + |
221 | + auto buffer_it = std::find_if( |
222 | + locked_buffers->begin(), |
223 | + locked_buffers->end(), |
224 | + [&output](auto const& candidate) |
225 | + { |
226 | + return candidate.first == output.drm_fd(); |
227 | + }); |
228 | + |
229 | + if (buffer_it != locked_buffers->end()) |
230 | + { |
231 | + return buffer_it->second; |
232 | + } |
233 | + |
234 | + locked_buffers->push_back(std::make_pair(output.drm_fd(), GBMBOWrapper(output.drm_fd()))); |
235 | + |
236 | + gbm_bo* bo = locked_buffers->back().second; |
237 | + if (gbm_bo_get_width(bo) < min_buffer_width) |
238 | + { |
239 | + min_buffer_width = gbm_bo_get_width(bo); |
240 | + } |
241 | + if (gbm_bo_get_height(bo) < min_buffer_height) |
242 | + { |
243 | + min_buffer_height = gbm_bo_get_height(bo); |
244 | + } |
245 | + |
246 | + return bo; |
247 | +} |
248 | |
249 | === modified file 'src/platforms/mesa/server/kms/cursor.h' |
250 | --- src/platforms/mesa/server/kms/cursor.h 2017-05-25 02:47:48 +0000 |
251 | +++ src/platforms/mesa/server/kms/cursor.h 2017-06-09 10:22:51 +0000 |
252 | @@ -25,12 +25,14 @@ |
253 | #include "mir/geometry/displacement.h" |
254 | |
255 | #include "mir_toolkit/common.h" |
256 | +#include "mutex.h" |
257 | |
258 | #include <gbm.h> |
259 | |
260 | #include <functional> |
261 | #include <memory> |
262 | #include <mutex> |
263 | +#include <vector> |
264 | |
265 | namespace mir |
266 | { |
267 | @@ -67,7 +69,6 @@ |
268 | { |
269 | public: |
270 | Cursor( |
271 | - gbm_device* device, |
272 | KMSOutputContainer& output_container, |
273 | std::shared_ptr<CurrentConfiguration> const& current_configuration); |
274 | |
275 | @@ -87,9 +88,18 @@ |
276 | void for_each_used_output(std::function<void(KMSOutput&, geometry::Rectangle const&, MirOrientation orientation)> const& f); |
277 | void place_cursor_at(geometry::Point position, ForceCursorState force_state); |
278 | void place_cursor_at_locked(std::lock_guard<std::mutex> const&, geometry::Point position, ForceCursorState force_state); |
279 | - void write_buffer_data_locked(std::lock_guard<std::mutex> const&, void const* data, size_t count); |
280 | - void pad_and_write_image_data_locked(std::lock_guard<std::mutex> const&, CursorImage const& image); |
281 | + void write_buffer_data_locked( |
282 | + std::lock_guard<std::mutex> const&, |
283 | + gbm_bo* buffer, |
284 | + void const* data, |
285 | + size_t count); |
286 | + void pad_and_write_image_data_locked( |
287 | + std::lock_guard<std::mutex> const&, |
288 | + gbm_bo* buffer, |
289 | + CursorImage const& image); |
290 | void clear(std::lock_guard<std::mutex> const&); |
291 | + |
292 | + gbm_bo* buffer_for_output(KMSOutput const& output); |
293 | |
294 | std::mutex guard; |
295 | |
296 | @@ -102,17 +112,21 @@ |
297 | |
298 | struct GBMBOWrapper |
299 | { |
300 | - GBMBOWrapper(gbm_device* gbm); |
301 | + GBMBOWrapper(int fd); |
302 | operator gbm_bo*(); |
303 | ~GBMBOWrapper(); |
304 | + |
305 | + GBMBOWrapper(GBMBOWrapper&& from); |
306 | private: |
307 | + gbm_device* device; |
308 | gbm_bo* buffer; |
309 | GBMBOWrapper(GBMBOWrapper const&) = delete; |
310 | GBMBOWrapper& operator=(GBMBOWrapper const&) = delete; |
311 | - } buffer; |
312 | + }; |
313 | + Mutex<std::vector<std::pair<int, GBMBOWrapper>>> buffers; |
314 | |
315 | - uint32_t buffer_width; |
316 | - uint32_t buffer_height; |
317 | + uint32_t min_buffer_width; |
318 | + uint32_t min_buffer_height; |
319 | |
320 | std::shared_ptr<CurrentConfiguration> const current_configuration; |
321 | }; |
322 | |
323 | === modified file 'src/platforms/mesa/server/kms/display.cpp' |
324 | --- src/platforms/mesa/server/kms/display.cpp 2017-05-08 03:04:26 +0000 |
325 | +++ src/platforms/mesa/server/kms/display.cpp 2017-06-09 10:22:51 +0000 |
326 | @@ -339,17 +339,6 @@ |
327 | |
328 | auto mgm::Display::create_hardware_cursor() -> std::shared_ptr<graphics::Cursor> |
329 | { |
330 | - /* |
331 | - * TODO: Using the hardware cursor in a hybrid-output situation requires making |
332 | - * mgm::Cursor hybrid-aware so it can create a cursor bo on each GPU. |
333 | - * |
334 | - * For a first cut, just disable the hardware cursor on hybrid systems. |
335 | - */ |
336 | - if (drm.size() > 1) |
337 | - { |
338 | - return nullptr; |
339 | - } |
340 | - |
341 | // There is only one hardware cursor. We do not keep a strong reference to it in the display though, |
342 | // if no other component of Mir is interested (i.e. the input stack does not keep a reference to send |
343 | // position updates) we must be configured not to use a cursor and thusly let it deallocate. |
344 | @@ -377,9 +366,9 @@ |
345 | |
346 | try |
347 | { |
348 | - locked_cursor = std::make_shared<Cursor>(gbm->device, |
349 | - *output_container, |
350 | - std::make_shared<KMSCurrentConfiguration>(*this)); |
351 | + locked_cursor = std::make_shared<Cursor>( |
352 | + *output_container, |
353 | + std::make_shared<KMSCurrentConfiguration>(*this)); |
354 | } |
355 | catch (std::runtime_error const&) |
356 | { |
357 | |
358 | === added file 'src/platforms/mesa/server/kms/mutex.h' |
359 | --- src/platforms/mesa/server/kms/mutex.h 1970-01-01 00:00:00 +0000 |
360 | +++ src/platforms/mesa/server/kms/mutex.h 2017-06-09 10:22:51 +0000 |
361 | @@ -0,0 +1,104 @@ |
362 | +/* |
363 | + * Copyright © 2017 Canonical Ltd. |
364 | + * |
365 | + * This program is free software: you can redistribute it and/or modify it |
366 | + * under the terms of the GNU Lesser General Public License version 3, |
367 | + * as published by the Free Software Foundation. |
368 | + * |
369 | + * This program is distributed in the hope that it will be useful, |
370 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
371 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
372 | + * GNU Lesser General Public License for more details. |
373 | + * |
374 | + * You should have received a copy of the GNU Lesser General Public License |
375 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
376 | + * |
377 | + * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com> |
378 | + */ |
379 | + |
380 | +#ifndef MIR_MUTEX_H_ |
381 | +#define MIR_MUTEX_H_ |
382 | + |
383 | +#include <mutex> |
384 | + |
385 | +namespace mir |
386 | +{ |
387 | +/** |
388 | + * Smart-pointer-esque accessor for Mutex<> protected data. |
389 | + * |
390 | + * Ensures exclusive access to the referenced data. |
391 | + * |
392 | + * \tparam Guarded Type of data guarded by the mutex. |
393 | + */ |
394 | +template<typename Guarded> |
395 | +class MutexGuard |
396 | +{ |
397 | +public: |
398 | + MutexGuard(std::unique_lock<std::mutex>&& lock, Guarded& value) |
399 | + : value{value}, |
400 | + lock{std::move(lock)} |
401 | + { |
402 | + } |
403 | + MutexGuard(MutexGuard&& from) = default; |
404 | + ~MutexGuard() noexcept(false) |
405 | + { |
406 | + if (lock.owns_lock()) |
407 | + { |
408 | + lock.unlock(); |
409 | + } |
410 | + } |
411 | + |
412 | + Guarded& operator*() |
413 | + { |
414 | + return value; |
415 | + } |
416 | + Guarded* operator->() |
417 | + { |
418 | + return &value; |
419 | + } |
420 | +private: |
421 | + Guarded& value; |
422 | + std::unique_lock<std::mutex> lock; |
423 | +}; |
424 | + |
425 | +/** |
426 | + * A data-locking mutex |
427 | + * |
428 | + * This is a mutex which owns the data it guards, and can give out a |
429 | + * smart-pointer-esque lock to lock and access it. |
430 | + * |
431 | + * \tparam Guarded The type of data guarded by the mutex |
432 | + */ |
433 | +template<typename Guarded> |
434 | +class Mutex |
435 | +{ |
436 | +public: |
437 | + Mutex() = default; |
438 | + Mutex(Guarded&& initial_value) |
439 | + : value{std::move(initial_value)} |
440 | + { |
441 | + } |
442 | + |
443 | + Mutex(Mutex const&) = delete; |
444 | + Mutex& operator=(Mutex const&) = delete; |
445 | + |
446 | + /** |
447 | + * Lock the mutex and return an accessor for the protected data. |
448 | + * |
449 | + * \return A smart-pointer-esque accessor for the contained data. |
450 | + * While code has access to the MutexGuard it is guaranteed to have exclusive |
451 | + * access to the contained data. |
452 | + */ |
453 | + MutexGuard<Guarded> lock() |
454 | + { |
455 | + return MutexGuard<Guarded>{std::unique_lock<std::mutex>{mutex}, value}; |
456 | + } |
457 | + |
458 | +private: |
459 | + std::mutex mutex; |
460 | + Guarded value; |
461 | +}; |
462 | + |
463 | +} |
464 | + |
465 | +#endif //MIR_MUTEX_H_ |
466 | |
467 | === modified file 'tests/unit-tests/platforms/mesa/kms/test_cursor.cpp' |
468 | --- tests/unit-tests/platforms/mesa/kms/test_cursor.cpp 2017-05-08 03:04:26 +0000 |
469 | +++ tests/unit-tests/platforms/mesa/kms/test_cursor.cpp 2017-06-09 10:22:51 +0000 |
470 | @@ -300,7 +300,7 @@ |
471 | |
472 | size_t const cursor_side{64}; |
473 | MesaCursorTest() |
474 | - : cursor{mock_gbm.fake_gbm.device, output_container, |
475 | + : cursor{output_container, |
476 | mt::fake_shared(current_configuration)} |
477 | { |
478 | using namespace ::testing; |
479 | @@ -351,7 +351,7 @@ |
480 | GBM_FORMAT_ARGB8888, |
481 | GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE)); |
482 | |
483 | - mgm::Cursor cursor_tmp{mock_gbm.fake_gbm.device, output_container, |
484 | + mgm::Cursor cursor_tmp{output_container, |
485 | std::make_shared<StubCurrentConfiguration>(output_container)}; |
486 | } |
487 | |
488 | @@ -359,10 +359,11 @@ |
489 | { |
490 | using namespace ::testing; |
491 | |
492 | - EXPECT_CALL(mock_gbm, gbm_bo_get_width(_)); |
493 | - EXPECT_CALL(mock_gbm, gbm_bo_get_height(_)); |
494 | + // Our standard mock DRM has 2 GPU devices, and we should construct a cursor on both. |
495 | + EXPECT_CALL(mock_gbm, gbm_bo_get_width(_)).Times(2); |
496 | + EXPECT_CALL(mock_gbm, gbm_bo_get_height(_)).Times(2); |
497 | |
498 | - mgm::Cursor cursor_tmp{mock_gbm.fake_gbm.device, output_container, |
499 | + mgm::Cursor cursor_tmp{output_container, |
500 | std::make_shared<StubCurrentConfiguration>(output_container)}; |
501 | } |
502 | |
503 | @@ -377,7 +378,7 @@ |
504 | |
505 | EXPECT_CALL(mock_gbm, gbm_bo_create(_, drm_buffer_size, drm_buffer_size, _, _)); |
506 | |
507 | - mgm::Cursor cursor_tmp{mock_gbm.fake_gbm.device, output_container, |
508 | + mgm::Cursor cursor_tmp{output_container, |
509 | std::make_shared<StubCurrentConfiguration>(output_container)}; |
510 | } |
511 | |
512 | @@ -394,7 +395,7 @@ |
513 | |
514 | EXPECT_CALL(mock_gbm, gbm_bo_create(_, 64, 64, _, _)); |
515 | |
516 | - mgm::Cursor cursor_tmp{mock_gbm.fake_gbm.device, output_container, |
517 | + mgm::Cursor cursor_tmp{output_container, |
518 | std::make_shared<StubCurrentConfiguration>(output_container)}; |
519 | } |
520 | |
521 | @@ -458,7 +459,7 @@ |
522 | |
523 | EXPECT_CALL(mock_gbm, gbm_bo_write(mock_gbm.fake_gbm.bo, ContainsASingleWhitePixel(width*height), buffer_size_bytes)); |
524 | |
525 | - mgm::Cursor cursor_tmp{mock_gbm.fake_gbm.device, output_container, |
526 | + mgm::Cursor cursor_tmp{output_container, |
527 | std::make_shared<StubCurrentConfiguration>(output_container)}; |
528 | cursor_tmp.show(SinglePixelCursorImage()); |
529 | } |
530 | @@ -495,7 +496,7 @@ |
531 | EXPECT_CALL(*output_container.outputs[1], has_cursor()).Times(0); |
532 | EXPECT_CALL(*output_container.outputs[2], has_cursor()).Times(0); |
533 | |
534 | - mgm::Cursor cursor_tmp{mock_gbm.fake_gbm.device, output_container, |
535 | + mgm::Cursor cursor_tmp{output_container, |
536 | std::make_shared<StubCurrentConfiguration>(output_container)}; |
537 | |
538 | output_container.verify_and_clear_expectations(); |
539 | @@ -513,7 +514,7 @@ |
540 | .WillByDefault(Return(false)); |
541 | |
542 | EXPECT_THROW( |
543 | - mgm::Cursor cursor_tmp(mock_gbm.fake_gbm.device, output_container, |
544 | + mgm::Cursor cursor_tmp(output_container, |
545 | std::make_shared<StubCurrentConfiguration>(output_container)); |
546 | , std::runtime_error); |
547 | } |
FAILED: Continuous integration, rev:4086 /mir-jenkins. ubuntu. com/job/ mir-ci/ 3208/ /mir-jenkins. ubuntu. com/job/ build-mir/ 4317/console /mir-jenkins. ubuntu. com/job/ build-0- fetch/4404/ console /mir-jenkins. ubuntu. com/job/ build-1- sourcepkg/ release= vivid+overlay/ 4394/console /mir-jenkins. ubuntu. com/job/ build-1- sourcepkg/ release= xenial+ overlay/ 4394/console /mir-jenkins. ubuntu. com/job/ build-1- sourcepkg/ release= zesty/4394/ console /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= clang,platform= mesa,release= zesty/4349/ console /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= gcc,platform= mesa,release= xenial+ overlay/ 4349/console /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= gcc,platform= mesa,release= zesty/4349/ console /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= cross-armhf, compiler= gcc,platform= android, release= vivid+overlay/ 4349/console /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= i386,compiler= gcc,platform= android, release= vivid+overlay/ 4349/console /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= i386,compiler= gcc,platform= mesa,release= xenial+ overlay/ 4349/console
https:/
Executed test runs:
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild: /mir-jenkins. ubuntu. com/job/ mir-ci/ 3208/rebuild
https:/