Mir

Merge lp:~raof/mir/mesa-hybrid-cursor into lp:mir

Proposed by Chris Halse Rogers
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
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.

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

FAILED: Continuous integration, rev:4086
https://mir-jenkins.ubuntu.com/job/mir-ci/3208/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/4317/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-0-fetch/4404/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/4394/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial+overlay/4394/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/4394/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4349/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/4349/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4349/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/4349/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/4349/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/4349/console

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

review: Needs Fixing (continuous-integration)
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

FAILED: Continuous integration, rev:4087
https://mir-jenkins.ubuntu.com/job/mir-ci/3218/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/4331/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/4418
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/4408
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial+overlay/4408
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/4408
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4363
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4363/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/4363/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4363/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/4363/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/4363/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/4363/console

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

review: Needs Fixing (continuous-integration)
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

FAILED: Continuous integration, rev:4087
https://mir-jenkins.ubuntu.com/job/mir-ci/3247/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/4371/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/4458
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/4448
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial+overlay/4448
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/4448
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4403
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4403/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/4403/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4403/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/4403/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/4403/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/4403/console

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

review: Needs Fixing (continuous-integration)
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

FAILED: Continuous integration, rev:4088
https://mir-jenkins.ubuntu.com/job/mir-ci/3273/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/4413/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/4505
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/4495
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial+overlay/4495
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/4495
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4445
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4445/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/4445/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4445/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/4445/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/4445/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/4445/console

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

review: Needs Fixing (continuous-integration)
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

FAILED: Continuous integration, rev:4088
https://mir-jenkins.ubuntu.com/job/mir-ci/3350/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/4524/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/4642
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/4631
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/4631
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial+overlay/4631
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/4631
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4555
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4555/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/4555/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4555/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/4555/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/4555/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/4555/console

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

review: Needs Fixing (continuous-integration)
Revision history for this message
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?

review: Needs Information
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

FAILED: Continuous integration, rev:4088
https://mir-jenkins.ubuntu.com/job/mir-ci/3443/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/4689/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/4824
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=artful/4814
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/4814
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/4814
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=artful/4726
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=artful/4726/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4726
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4726/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=artful/4726/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/4726/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4726/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=artful/4726/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/4726/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/4726/console

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

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

It's still worth merging. Once it builds, it seems!

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/common/CMakeLists.txt'
--- src/common/CMakeLists.txt 2017-02-15 14:45:41 +0000
+++ src/common/CMakeLists.txt 2017-03-29 05:01:14 +0000
@@ -20,7 +20,8 @@
20 $<TARGET_OBJECTS:mirtime>20 $<TARGET_OBJECTS:mirtime>
21 ${CMAKE_CURRENT_SOURCE_DIR}/output_type_names.cpp21 ${CMAKE_CURRENT_SOURCE_DIR}/output_type_names.cpp
22 ${CMAKE_CURRENT_SOURCE_DIR}/log.cpp22 ${CMAKE_CURRENT_SOURCE_DIR}/log.cpp
23 ${CMAKE_CURRENT_SOURCE_DIR}/libname.cpp ${PROJECT_SOURCE_DIR}/include/common/mir/libname.h23 ${CMAKE_CURRENT_SOURCE_DIR}/libname.cpp
24 ${PROJECT_SOURCE_DIR}/include/common/mir/libname.h
24 ${PROJECT_SOURCE_DIR}/include/common/mir/posix_rw_mutex.h25 ${PROJECT_SOURCE_DIR}/include/common/mir/posix_rw_mutex.h
25 posix_rw_mutex.cpp26 posix_rw_mutex.cpp
26 edid.cpp27 edid.cpp
2728
=== modified file 'src/platforms/mesa/server/kms/CMakeLists.txt'
--- src/platforms/mesa/server/kms/CMakeLists.txt 2017-03-29 05:01:13 +0000
+++ src/platforms/mesa/server/kms/CMakeLists.txt 2017-03-29 05:01:14 +0000
@@ -44,6 +44,7 @@
44 real_kms_output_container.cpp44 real_kms_output_container.cpp
45 egl_helper.h45 egl_helper.h
46 egl_helper.cpp46 egl_helper.cpp
47 mutex.h
47)48)
4849
49configure_file(${CMAKE_CURRENT_SOURCE_DIR}/symbols.map.in50configure_file(${CMAKE_CURRENT_SOURCE_DIR}/symbols.map.in
5051
=== modified file 'src/platforms/mesa/server/kms/cursor.cpp'
--- src/platforms/mesa/server/kms/cursor.cpp 2017-03-10 10:20:24 +0000
+++ src/platforms/mesa/server/kms/cursor.cpp 2017-03-29 05:01:14 +0000
@@ -88,34 +88,73 @@
88 drmGetCap(fd, DRM_CAP_CURSOR_WIDTH, &width);88 drmGetCap(fd, DRM_CAP_CURSOR_WIDTH, &width);
89 return int(width);89 return int(width);
90}90}
91}91
9292gbm_device* gbm_create_device_checked(int fd)
93mgm::Cursor::GBMBOWrapper::GBMBOWrapper(gbm_device* gbm) :93{
94 buffer(gbm_bo_create(94 auto device = gbm_create_device(fd);
95 gbm,95 if (!device)
96 get_drm_cursor_width(gbm_device_get_fd(gbm)),96 {
97 get_drm_cursor_height(gbm_device_get_fd(gbm)),97 BOOST_THROW_EXCEPTION(std::runtime_error("Failed to create gbm device"));
98 GBM_FORMAT_ARGB8888,98 }
99 GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE))99 return device;
100}
101}
102
103mgm::Cursor::GBMBOWrapper::GBMBOWrapper(int fd) :
104 device{gbm_create_device_checked(fd)},
105 buffer{
106 gbm_bo_create(
107 device,
108 get_drm_cursor_width(fd),
109 get_drm_cursor_height(fd),
110 GBM_FORMAT_ARGB8888,
111 GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE)}
100{112{
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"));
102}114}
103115
104inline mgm::Cursor::GBMBOWrapper::operator gbm_bo*() { return buffer; }116inline mgm::Cursor::GBMBOWrapper::operator gbm_bo*()
105inline mgm::Cursor::GBMBOWrapper::~GBMBOWrapper() { gbm_bo_destroy(buffer); }117{
118 return buffer;
119}
120
121inline mgm::Cursor::GBMBOWrapper::~GBMBOWrapper()
122{
123 if (device)
124 gbm_device_destroy(device);
125 if (buffer)
126 gbm_bo_destroy(buffer);
127}
128
129mgm::Cursor::GBMBOWrapper::GBMBOWrapper(GBMBOWrapper&& from)
130 : device{from.device},
131 buffer{from.buffer}
132{
133 const_cast<gbm_bo*&>(from.buffer) = nullptr;
134 const_cast<gbm_device*&>(from.device) = nullptr;
135}
106136
107mgm::Cursor::Cursor(137mgm::Cursor::Cursor(
108 gbm_device* gbm,
109 KMSOutputContainer& output_container,138 KMSOutputContainer& output_container,
110 std::shared_ptr<CurrentConfiguration> const& current_configuration) :139 std::shared_ptr<CurrentConfiguration> const& current_configuration) :
111 output_container(output_container),140 output_container(output_container),
112 current_position(),141 current_position(),
113 last_set_failed(false),142 last_set_failed(false),
114 buffer(gbm),143 min_buffer_width{std::numeric_limits<uint32_t>::max()},
115 buffer_width(gbm_bo_get_width(buffer)),144 min_buffer_height{std::numeric_limits<uint32_t>::max()},
116 buffer_height(gbm_bo_get_height(buffer)),
117 current_configuration(current_configuration)145 current_configuration(current_configuration)
118{146{
147 // Generate the buffers for the initial configuration.
148 current_configuration->with_current_configuration_do(
149 [this](KMSDisplayConfiguration const& kms_conf)
150 {
151 kms_conf.for_each_output(
152 [this, &kms_conf](auto const& output)
153 {
154 buffer_for_output(*kms_conf.get_output_for(output.id));
155 });
156 });
157
119 hide();158 hide();
120 if (last_set_failed)159 if (last_set_failed)
121 throw std::runtime_error("Initial KMS cursor set failed");160 throw std::runtime_error("Initial KMS cursor set failed");
@@ -126,7 +165,11 @@
126 hide();165 hide();
127}166}
128167
129void mgm::Cursor::write_buffer_data_locked(std::lock_guard<std::mutex> const&, void const* data, size_t count)168void mgm::Cursor::write_buffer_data_locked(
169 std::lock_guard<std::mutex> const&,
170 gbm_bo* buffer,
171 void const* data,
172 size_t count)
130{173{
131 if (auto result = gbm_bo_write(buffer, data, count))174 if (auto result = gbm_bo_write(buffer, data, count))
132 {175 {
@@ -136,20 +179,23 @@
136 }179 }
137}180}
138181
139void mgm::Cursor::pad_and_write_image_data_locked(std::lock_guard<std::mutex> const& lg, CursorImage const& image)182void mgm::Cursor::pad_and_write_image_data_locked(
183 std::lock_guard<std::mutex> const& lg,
184 gbm_bo* buffer,
185 CursorImage const& image)
140{186{
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());
142 auto image_width = image.size().width.as_uint32_t();188 auto image_width = image.size().width.as_uint32_t();
143 auto image_height = image.size().height.as_uint32_t();189 auto image_height = image.size().height.as_uint32_t();
144 auto image_stride = image_width * 4;190 auto image_stride = image_width * 4;
145191
146 if (image_width > buffer_width || image_height > buffer_height)192 if (image_width > min_buffer_width || image_height > min_buffer_height)
147 {193 {
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"));
149 }195 }
150 196
151 size_t buffer_stride = gbm_bo_get_stride(buffer); // in bytes197 size_t buffer_stride = gbm_bo_get_stride(buffer); // in bytes
152 size_t padded_size = buffer_stride * buffer_height;198 size_t padded_size = buffer_stride * gbm_bo_get_height(buffer);
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]);
154 size_t rhs_padding = buffer_stride - image_stride;200 size_t rhs_padding = buffer_stride - image_stride;
155201
@@ -164,9 +210,9 @@
164 src += image_stride;210 src += image_stride;
165 }211 }
166212
167 memset(dest, 0, buffer_stride * (buffer_height - image_height));213 memset(dest, 0, buffer_stride * (gbm_bo_get_height(buffer) - image_height));
168214
169 write_buffer_data_locked(lg, &padded[0], padded_size);215 write_buffer_data_locked(lg, buffer, &padded[0], padded_size);
170}216}
171217
172void mgm::Cursor::show()218void mgm::Cursor::show()
@@ -186,14 +232,20 @@
186232
187 auto const& size = cursor_image.size();233 auto const& size = cursor_image.size();
188234
189 if (size != geometry::Size{buffer_width, buffer_height})235 {
190 {236 auto locked_buffers = buffers.lock();
191 pad_and_write_image_data_locked(lg, cursor_image);237 for (auto& pair : *locked_buffers)
192 }238 {
193 else239 auto& buffer = pair.second;
194 {240 if (size != geometry::Size{gbm_bo_get_width(buffer), gbm_bo_get_height(buffer)})
195 auto const count = size.width.as_uint32_t() * size.height.as_uint32_t() * sizeof(uint32_t);241 {
196 write_buffer_data_locked(lg, cursor_image.as_argb_8888(), count);242 pad_and_write_image_data_locked(lg, buffer, cursor_image);
243 } else
244 {
245 auto const count = size.width.as_uint32_t() * size.height.as_uint32_t() * sizeof(uint32_t);
246 write_buffer_data_locked(lg, buffer, cursor_image.as_argb_8888(), count);
247 }
248 }
197 }249 }
198 hotspot = cursor_image.hotspot();250 hotspot = cursor_image.hotspot();
199 251
@@ -288,7 +340,7 @@
288 output.move_cursor(geom::Point{} + dp - hotspot);340 output.move_cursor(geom::Point{} + dp - hotspot);
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..
290 {342 {
291 if (!output.set_cursor(buffer) || !output.has_cursor())343 if (!output.set_cursor(buffer_for_output(output)) || !output.has_cursor())
292 set_on_all_outputs = false;344 set_on_all_outputs = false;
293 }345 }
294 }346 }
@@ -303,3 +355,35 @@
303355
304 last_set_failed = !set_on_all_outputs;356 last_set_failed = !set_on_all_outputs;
305}357}
358
359gbm_bo* mgm::Cursor::buffer_for_output(KMSOutput const& output)
360{
361 auto locked_buffers = buffers.lock();
362
363 auto buffer_it = std::find_if(
364 locked_buffers->begin(),
365 locked_buffers->end(),
366 [&output](auto const& candidate)
367 {
368 return candidate.first == output.drm_fd();
369 });
370
371 if (buffer_it != locked_buffers->end())
372 {
373 return buffer_it->second;
374 }
375
376 locked_buffers->push_back(std::make_pair(output.drm_fd(), GBMBOWrapper(output.drm_fd())));
377
378 gbm_bo* bo = locked_buffers->back().second;
379 if (gbm_bo_get_width(bo) < min_buffer_width)
380 {
381 min_buffer_width = gbm_bo_get_width(bo);
382 }
383 if (gbm_bo_get_height(bo) < min_buffer_height)
384 {
385 min_buffer_height = gbm_bo_get_height(bo);
386 }
387
388 return bo;
389}
306390
=== modified file 'src/platforms/mesa/server/kms/cursor.h'
--- src/platforms/mesa/server/kms/cursor.h 2017-02-15 07:38:33 +0000
+++ src/platforms/mesa/server/kms/cursor.h 2017-03-29 05:01:14 +0000
@@ -25,11 +25,13 @@
25#include "mir/geometry/displacement.h"25#include "mir/geometry/displacement.h"
2626
27#include "mir_toolkit/common.h"27#include "mir_toolkit/common.h"
28#include "mutex.h"
2829
29#include <gbm.h>30#include <gbm.h>
3031
31#include <memory>32#include <memory>
32#include <mutex>33#include <mutex>
34#include <vector>
3335
34namespace mir36namespace mir
35{37{
@@ -66,7 +68,6 @@
66{68{
67public:69public:
68 Cursor(70 Cursor(
69 gbm_device* device,
70 KMSOutputContainer& output_container,71 KMSOutputContainer& output_container,
71 std::shared_ptr<CurrentConfiguration> const& current_configuration);72 std::shared_ptr<CurrentConfiguration> const& current_configuration);
7273
@@ -86,9 +87,18 @@
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);
87 void place_cursor_at(geometry::Point position, ForceCursorState force_state);88 void place_cursor_at(geometry::Point position, ForceCursorState force_state);
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);
89 void write_buffer_data_locked(std::lock_guard<std::mutex> const&, void const* data, size_t count);90 void write_buffer_data_locked(
90 void pad_and_write_image_data_locked(std::lock_guard<std::mutex> const&, CursorImage const& image);91 std::lock_guard<std::mutex> const&,
92 gbm_bo* buffer,
93 void const* data,
94 size_t count);
95 void pad_and_write_image_data_locked(
96 std::lock_guard<std::mutex> const&,
97 gbm_bo* buffer,
98 CursorImage const& image);
91 void clear(std::lock_guard<std::mutex> const&);99 void clear(std::lock_guard<std::mutex> const&);
100
101 gbm_bo* buffer_for_output(KMSOutput const& output);
92 102
93 std::mutex guard;103 std::mutex guard;
94104
@@ -101,17 +111,21 @@
101111
102 struct GBMBOWrapper112 struct GBMBOWrapper
103 {113 {
104 GBMBOWrapper(gbm_device* gbm);114 GBMBOWrapper(int fd);
105 operator gbm_bo*();115 operator gbm_bo*();
106 ~GBMBOWrapper();116 ~GBMBOWrapper();
117
118 GBMBOWrapper(GBMBOWrapper&& from);
107 private:119 private:
108 gbm_bo* buffer;120 gbm_device* const device;
121 gbm_bo* const buffer;
109 GBMBOWrapper(GBMBOWrapper const&) = delete;122 GBMBOWrapper(GBMBOWrapper const&) = delete;
110 GBMBOWrapper& operator=(GBMBOWrapper const&) = delete;123 GBMBOWrapper& operator=(GBMBOWrapper const&) = delete;
111 } buffer;124 };
125 Mutex<std::vector<std::pair<int, GBMBOWrapper>>> buffers;
112126
113 uint32_t buffer_width;127 uint32_t min_buffer_width;
114 uint32_t buffer_height;128 uint32_t min_buffer_height;
115129
116 std::shared_ptr<CurrentConfiguration> const current_configuration;130 std::shared_ptr<CurrentConfiguration> const current_configuration;
117};131};
118132
=== modified file 'src/platforms/mesa/server/kms/display.cpp'
--- src/platforms/mesa/server/kms/display.cpp 2017-03-29 05:01:13 +0000
+++ src/platforms/mesa/server/kms/display.cpp 2017-03-29 05:01:14 +0000
@@ -260,17 +260,6 @@
260260
261auto mgm::Display::create_hardware_cursor() -> std::shared_ptr<graphics::Cursor>261auto mgm::Display::create_hardware_cursor() -> std::shared_ptr<graphics::Cursor>
262{262{
263 /*
264 * TODO: Using the hardware cursor in a hybrid-output situation requires making
265 * mgm::Cursor hybrid-aware so it can create a cursor bo on each GPU.
266 *
267 * For a first cut, just disable the hardware cursor on hybrid systems.
268 */
269 if (drm.size() > 1)
270 {
271 return nullptr;
272 }
273
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,
275 // if no other component of Mir is interested (i.e. the input stack does not keep a reference to send264 // if no other component of Mir is interested (i.e. the input stack does not keep a reference to send
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.
@@ -298,9 +287,9 @@
298287
299 try288 try
300 {289 {
301 locked_cursor = std::make_shared<Cursor>(gbm->device,290 locked_cursor = std::make_shared<Cursor>(
302 *output_container,291 *output_container,
303 std::make_shared<KMSCurrentConfiguration>(*this));292 std::make_shared<KMSCurrentConfiguration>(*this));
304 }293 }
305 catch (std::runtime_error const&)294 catch (std::runtime_error const&)
306 {295 {
307296
=== added file 'src/platforms/mesa/server/kms/mutex.h'
--- src/platforms/mesa/server/kms/mutex.h 1970-01-01 00:00:00 +0000
+++ src/platforms/mesa/server/kms/mutex.h 2017-03-29 05:01:14 +0000
@@ -0,0 +1,104 @@
1/*
2 * Copyright © 2017 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License version 3,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
17 */
18
19#ifndef MIR_MUTEX_H_
20#define MIR_MUTEX_H_
21
22#include <mutex>
23
24namespace mir
25{
26/**
27 * Smart-pointer-esque accessor for Mutex<> protected data.
28 *
29 * Ensures exclusive access to the referenced data.
30 *
31 * \tparam Guarded Type of data guarded by the mutex.
32 */
33template<typename Guarded>
34class MutexGuard
35{
36public:
37 MutexGuard(std::unique_lock<std::mutex>&& lock, Guarded& value)
38 : value{value},
39 lock{std::move(lock)}
40 {
41 }
42 MutexGuard(MutexGuard&& from) = default;
43 ~MutexGuard() noexcept(false)
44 {
45 if (lock.owns_lock())
46 {
47 lock.unlock();
48 }
49 }
50
51 Guarded& operator*()
52 {
53 return value;
54 }
55 Guarded* operator->()
56 {
57 return &value;
58 }
59private:
60 Guarded& value;
61 std::unique_lock<std::mutex> lock;
62};
63
64/**
65 * A data-locking mutex
66 *
67 * This is a mutex which owns the data it guards, and can give out a
68 * smart-pointer-esque lock to lock and access it.
69 *
70 * \tparam Guarded The type of data guarded by the mutex
71 */
72template<typename Guarded>
73class Mutex
74{
75public:
76 Mutex() = default;
77 Mutex(Guarded&& initial_value)
78 : value{std::move(initial_value)}
79 {
80 }
81
82 Mutex(Mutex const&) = delete;
83 Mutex& operator=(Mutex const&) = delete;
84
85 /**
86 * Lock the mutex and return an accessor for the protected data.
87 *
88 * \return A smart-pointer-esque accessor for the contained data.
89 * While code has access to the MutexGuard it is guaranteed to have exclusive
90 * access to the contained data.
91 */
92 MutexGuard<Guarded> lock()
93 {
94 return MutexGuard<Guarded>{std::unique_lock<std::mutex>{mutex}, value};
95 }
96
97private:
98 std::mutex mutex;
99 Guarded value;
100};
101
102}
103
104#endif //MIR_MUTEX_H_
0105
=== modified file 'tests/unit-tests/platforms/mesa/kms/test_cursor.cpp'
--- tests/unit-tests/platforms/mesa/kms/test_cursor.cpp 2017-03-10 10:20:24 +0000
+++ tests/unit-tests/platforms/mesa/kms/test_cursor.cpp 2017-03-29 05:01:14 +0000
@@ -297,7 +297,7 @@
297297
298 size_t const cursor_side{64};298 size_t const cursor_side{64};
299 MesaCursorTest()299 MesaCursorTest()
300 : cursor{mock_gbm.fake_gbm.device, output_container,300 : cursor{output_container,
301 mt::fake_shared(current_configuration)}301 mt::fake_shared(current_configuration)}
302 {302 {
303 using namespace ::testing;303 using namespace ::testing;
@@ -348,7 +348,7 @@
348 GBM_FORMAT_ARGB8888,348 GBM_FORMAT_ARGB8888,
349 GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE));349 GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE));
350350
351 mgm::Cursor cursor_tmp{mock_gbm.fake_gbm.device, output_container,351 mgm::Cursor cursor_tmp{output_container,
352 std::make_shared<StubCurrentConfiguration>(output_container)};352 std::make_shared<StubCurrentConfiguration>(output_container)};
353}353}
354354
@@ -356,10 +356,11 @@
356{356{
357 using namespace ::testing;357 using namespace ::testing;
358358
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.
360 EXPECT_CALL(mock_gbm, gbm_bo_get_height(_));360 EXPECT_CALL(mock_gbm, gbm_bo_get_width(_)).Times(2);
361 EXPECT_CALL(mock_gbm, gbm_bo_get_height(_)).Times(2);
361362
362 mgm::Cursor cursor_tmp{mock_gbm.fake_gbm.device, output_container,363 mgm::Cursor cursor_tmp{output_container,
363 std::make_shared<StubCurrentConfiguration>(output_container)};364 std::make_shared<StubCurrentConfiguration>(output_container)};
364}365}
365366
@@ -374,7 +375,7 @@
374375
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, _, _));
376377
377 mgm::Cursor cursor_tmp{mock_gbm.fake_gbm.device, output_container,378 mgm::Cursor cursor_tmp{output_container,
378 std::make_shared<StubCurrentConfiguration>(output_container)};379 std::make_shared<StubCurrentConfiguration>(output_container)};
379}380}
380381
@@ -391,7 +392,7 @@
391392
392 EXPECT_CALL(mock_gbm, gbm_bo_create(_, 64, 64, _, _));393 EXPECT_CALL(mock_gbm, gbm_bo_create(_, 64, 64, _, _));
393394
394 mgm::Cursor cursor_tmp{mock_gbm.fake_gbm.device, output_container,395 mgm::Cursor cursor_tmp{output_container,
395 std::make_shared<StubCurrentConfiguration>(output_container)};396 std::make_shared<StubCurrentConfiguration>(output_container)};
396}397}
397398
@@ -455,7 +456,7 @@
455456
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));
457458
458 mgm::Cursor cursor_tmp{mock_gbm.fake_gbm.device, output_container,459 mgm::Cursor cursor_tmp{output_container,
459 std::make_shared<StubCurrentConfiguration>(output_container)};460 std::make_shared<StubCurrentConfiguration>(output_container)};
460 cursor_tmp.show(SinglePixelCursorImage());461 cursor_tmp.show(SinglePixelCursorImage());
461}462}
@@ -492,7 +493,7 @@
492 EXPECT_CALL(*output_container.outputs[1], has_cursor()).Times(0);493 EXPECT_CALL(*output_container.outputs[1], has_cursor()).Times(0);
493 EXPECT_CALL(*output_container.outputs[2], has_cursor()).Times(0);494 EXPECT_CALL(*output_container.outputs[2], has_cursor()).Times(0);
494495
495 mgm::Cursor cursor_tmp{mock_gbm.fake_gbm.device, output_container,496 mgm::Cursor cursor_tmp{output_container,
496 std::make_shared<StubCurrentConfiguration>(output_container)};497 std::make_shared<StubCurrentConfiguration>(output_container)};
497498
498 output_container.verify_and_clear_expectations();499 output_container.verify_and_clear_expectations();
@@ -510,7 +511,7 @@
510 .WillByDefault(Return(false));511 .WillByDefault(Return(false));
511512
512 EXPECT_THROW(513 EXPECT_THROW(
513 mgm::Cursor cursor_tmp(mock_gbm.fake_gbm.device, output_container,514 mgm::Cursor cursor_tmp(output_container,
514 std::make_shared<StubCurrentConfiguration>(output_container));515 std::make_shared<StubCurrentConfiguration>(output_container));
515 , std::runtime_error);516 , std::runtime_error);
516}517}

Subscribers

People subscribed via source and target branches