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