Mir

Merge lp:~andreas-pokorny/mir/fix-1391975 into lp:mir

Proposed by Andreas Pokorny
Status: Merged
Merged at revision: 2125
Proposed branch: lp:~andreas-pokorny/mir/fix-1391975
Merge into: lp:mir
Diff against target: 202 lines (+79/-28)
3 files modified
src/platform/graphics/mesa/cursor.cpp (+6/-5)
src/platform/graphics/mesa/cursor.h (+3/-0)
tests/unit-tests/graphics/mesa/test_cursor.cpp (+70/-23)
To merge this branch: bzr merge lp:~andreas-pokorny/mir/fix-1391975
Reviewer Review Type Date Requested Status
Daniel van Vugt Approve
Alberto Aguirre (community) Approve
Kevin DuBois (community) Needs Fixing
Robert Carr (community) Approve
PS Jenkins bot (community) continuous-integration Approve
Andreas Pokorny (community) Needs Information
Alexandros Frantzis (community) Needs Fixing
Review via email: mp+242940@code.launchpad.net

Commit message

Uses new DRM_CAP_CURSOR_WIDTH/HEIGHT to query maximum sizes for cursors and verifies the buffer size with gbm after allocation.

Kaveri based systems seem to provide 128x128 buffers whenever GBM_BO_USE_CURSOR is requested. (LP: #1391975)

Description of the change

This change adds some DRM capability test for cursor buffers, and only uses the buffer sizes reported by gbm_bo_get_width/height when writing cursor images. This should fix the graphical glitches seen on amd kaveri systems and possibly also on tegra.

To post a comment you must log in.
Revision history for this message
Alexandros Frantzis (afrantzis) wrote :

89 + struct CursorCapabilities
90 + {
91 + CursorCapabilities(int connection);
92 + uint64_t width, height;
93 + } cursor_cap;

Is there a reason to expose this in the header?

review: Needs Fixing
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Andreas Pokorny (andreas-pokorny) wrote :

> 89 + struct CursorCapabilities
> 90 + {
> 91 + CursorCapabilities(int connection);
> 92 + uint64_t width, height;
> 93 + } cursor_cap;
>
> Is there a reason to expose this in the header?

As of this revision, only convenience, I guess. cursor.h is not really visible... and it only burdens the header with int and uint64_t

I could also do an anonymous get_drm_cursor_cap_width.. it only exists that way because in a previous version I also used it as a buffer_width/buffer_height.

Revision history for this message
Andreas Pokorny (andreas-pokorny) wrote :

+ 78 and + 79 assume that drm drivers will provide us with sanely sized and supported cursor buffer sizes... That assumption might be wrong. Should I set a something like maximum to request?

review: Needs Information
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Daniel van Vugt (vanvugt) wrote :

OK, so GBM_BO_USE_CURSOR_64X64 is not being honoured by radeon. Sounds like the GBM header needs to remove "64X64" if that's not a bug and GBM is not required to honour the "64x64" dimensions.

But aside from learning to not trust the "64X64", there are still two possibilities:
(a) gbo_bo_get_width/height() returns the right answer. If so then just rely on that. No need to query drmGetCap; or
(b) gbm_bo_get_width/height() returns the wrong answer. If so then we need to do a fix entirely in Mesa/DRM.

So you have either:
  (a) Mir needs fixing, but a much simpler fix than this; or
  (b) Mir doesn't need fixing and Mesa/DRM does instead.

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

Actually, Mir needs fixing either way, to query the actual buffer width/height.

Revision history for this message
Andreas Pokorny (andreas-pokorny) wrote :

GBM_BO_USE_CURSOR_64X64 is just commented deprecated in gbm now. In my tests gbm_bo_get_width/height used to return the right size. drmGetCap is only a defensive addition to make sure that creating the buffer wont fail.

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

drmGetCap doesn't seem to be any more defensive than simply calling gbm_bo_get_width/height. In fact it might be more error-prone to risk requesting something that's not 64x64 for other drivers. So we should ensure we're always asking for 64x64 right now, but also be careful to query what we're actually given:
   gbm_bo_get_width
   gbm_bo_get_height

Revision history for this message
Robert Carr (robertcarr) wrote :

Looks like Alexandros concerned is addressed.

Not sure I understand Daniels concern. drmGetCap is used PRIOR to the gbm_bo existing and to choose the maximum width/height values which can be passed to gbm_bo_create. It's conceivable as per the API for example that you would see there is a 512x512 cursor buffer choose to allocate a 256x256 one and receive a 128x128 one in response. I cant imagine any situation where we dont want the maximum sized cursor buffer, but this does seem to be the only correct way to use the API.

>> but also be careful to query what we're actually given:
>> gbm_bo_get_width
>> gbm_bo_get_height

As this branch does.

Revision history for this message
Robert Carr (robertcarr) wrote :

+auto get_drm_cursor_width(int fd) -> int

I dont understand the point for usage of auto here.

90: whitespace
128: Is this the only option?
293: Debugging cout left in.

Looks ok to me though.

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

I was thinking in a more pure sense that we should only aim to fix a bug in a bug fix and not enhance at the same time. So in that way, always requesting 64x64 would eliminate the need for all the drmGetCap stuff.

But yeah, if the goal is to enhance and add support for larger cursors in the future then you do need to do it this way.

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

> + 78 and + 79 assume that drm drivers will provide us with sanely sized and
> supported cursor buffer sizes... That assumption might be wrong. Should I set
> a something like maximum to request?

Yes that's a big concern actually. A driver could feasibly have no small limitations. If it gives you 4096x4096 for example, we'd end up allocating 64MB just for a cursor.

We do need to impose some limit on the dimensions in our code. And if that limit is 64x64 then you might not need the drmGetCap stuff either :)

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

104 + GBMBOWrapper(gbm_device* gbm, int width, int height);
112/113
could be richer with geom::Size

l132, 32
duplicated defines

159 + .WillByDefault(Invoke([](int, uint64_t, uint64_t *val) -> int
160 + {
161 + *val = 64;
162 + return 1;
163 + })
164 + );
WillByDefault(DoAll(SetArgPointee<2>(64), Return(1)))

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

Since we're now in a world of dynamically sizeable cursor buffers, why not just make the cursor buffer the dimensions of the cursor image? :)

That's really an enhancement still though. If you wanted this branch out the way quickly, you could just continue asking for 64x64 and remember to gbm_bo_get_width/height. It's a trivially small change to just do that and declare the bug fixed.

Revision history for this message
Andreas Pokorny (andreas-pokorny) wrote :

> Since we're now in a world of dynamically sizeable cursor buffers, why not
> just make the cursor buffer the dimensions of the cursor image? :)
>
> That's really an enhancement still though. If you wanted this branch out the
> way quickly, you could just continue asking for 64x64 and remember to
> gbm_bo_get_width/height. It's a trivially small change to just do that and
> declare the bug fixed.

I believe we are not in that world yet. Drivers that support cursors through planes just have some fixed size plane allocated... And then still we get access to the whole buffer size. So it does not make sense to query for a weakly defined notion of cursor width and height capability, to then query the size, and then finally see what we received.

So yes reduced it a lot..

For larger cursors or for properly using pc hardware we should do the inverse anyhow. So just use planes and no cursors at all.. But that needs more work in several places.

Revision history for this message
Alberto Aguirre (albaguirre) wrote :

Looks much simpler :)

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

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/platform/graphics/mesa/cursor.cpp'
2--- src/platform/graphics/mesa/cursor.cpp 2014-12-04 03:47:52 +0000
3+++ src/platform/graphics/mesa/cursor.cpp 2014-12-04 10:08:41 +0000
4@@ -35,8 +35,7 @@
5
6 namespace
7 {
8-int const buffer_width = 64;
9-int const buffer_height = 64;
10+const uint64_t requested_cursor_size = 64;
11
12 // Transforms a relative position within the display bounds described by \a rect which is rotated with \a orientation
13 geom::Displacement transform(geom::Rectangle const& rect, geom::Displacement const& vector, MirOrientation orientation)
14@@ -59,10 +58,10 @@
15 mgm::Cursor::GBMBOWrapper::GBMBOWrapper(gbm_device* gbm) :
16 buffer(gbm_bo_create(
17 gbm,
18- buffer_width,
19- buffer_height,
20+ requested_cursor_size,
21+ requested_cursor_size,
22 GBM_FORMAT_ARGB8888,
23- GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE))
24+ GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE))
25 {
26 if (!buffer) BOOST_THROW_EXCEPTION(std::runtime_error("failed to create gbm buffer"));
27 }
28@@ -79,6 +78,8 @@
29 current_position(),
30 visible(true),
31 buffer(gbm),
32+ buffer_width(gbm_bo_get_width(buffer)),
33+ buffer_height(gbm_bo_get_height(buffer)),
34 current_configuration(current_configuration)
35 {
36 show(*initial_image);
37
38=== modified file 'src/platform/graphics/mesa/cursor.h'
39--- src/platform/graphics/mesa/cursor.h 2014-12-04 03:47:52 +0000
40+++ src/platform/graphics/mesa/cursor.h 2014-12-04 10:08:41 +0000
41@@ -108,6 +108,9 @@
42 GBMBOWrapper& operator=(GBMBOWrapper const&) = delete;
43 } buffer;
44
45+ uint32_t buffer_width;
46+ uint32_t buffer_height;
47+
48 std::shared_ptr<CurrentConfiguration> const current_configuration;
49 };
50 }
51
52=== modified file 'tests/unit-tests/graphics/mesa/test_cursor.cpp'
53--- tests/unit-tests/graphics/mesa/test_cursor.cpp 2014-12-04 03:47:52 +0000
54+++ tests/unit-tests/graphics/mesa/test_cursor.cpp 2014-12-04 10:08:41 +0000
55@@ -220,8 +220,22 @@
56 };
57 void const* StubCursorImage::image_data = reinterpret_cast<void*>(&StubCursorImage::image_data);
58
59-struct MesaCursorTest : public ::testing::Test
60+struct MesaCursorTest : ::testing::Test
61 {
62+ struct MockGBM : testing::NiceMock<mtd::MockGBM>
63+ {
64+ MockGBM()
65+ {
66+ using namespace ::testing;
67+ const uint32_t default_cursor_size = 64;
68+ ON_CALL(*this, gbm_bo_get_width(_))
69+ .WillByDefault(Return(default_cursor_size));
70+ ON_CALL(*this, gbm_bo_get_height(_))
71+ .WillByDefault(Return(default_cursor_size));
72+
73+ }
74+ } mock_gbm;
75+
76 MesaCursorTest()
77 : cursor{mock_gbm.fake_gbm.device, output_container,
78 mt::fake_shared(current_configuration),
79@@ -231,11 +245,26 @@
80
81 StubCurrentConfiguration current_configuration;
82 StubCursorImage stub_image;
83- testing::NiceMock<mtd::MockGBM> mock_gbm;
84 StubKMSOutputContainer output_container;
85 mgm::Cursor cursor;
86 };
87
88+struct SinglePixelCursorImage : public StubCursorImage
89+{
90+ geom::Size size() const
91+ {
92+ return small_cursor_size;
93+ }
94+ void const* as_argb_8888() const
95+ {
96+ static uint32_t const pixel = 0xffffffff;
97+ return &pixel;
98+ }
99+
100+ size_t const cursor_side{1};
101+ geom::Size const small_cursor_size{cursor_side, cursor_side};
102+};
103+
104 }
105
106 TEST_F(MesaCursorTest, creates_cursor_bo_image)
107@@ -244,7 +273,19 @@
108 EXPECT_CALL(mock_gbm, gbm_bo_create(mock_gbm.fake_gbm.device,
109 cursor_side, cursor_side,
110 GBM_FORMAT_ARGB8888,
111- GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE));
112+ GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE));
113+
114+ mgm::Cursor cursor_tmp{mock_gbm.fake_gbm.device, output_container,
115+ std::make_shared<StubCurrentConfiguration>(),
116+ std::make_shared<StubCursorImage>()};
117+}
118+
119+TEST_F(MesaCursorTest, queries_received_cursor_size)
120+{
121+ using namespace ::testing;
122+
123+ EXPECT_CALL(mock_gbm, gbm_bo_get_width(_));
124+ EXPECT_CALL(mock_gbm, gbm_bo_get_height(_));
125
126 mgm::Cursor cursor_tmp{mock_gbm.fake_gbm.device, output_container,
127 std::make_shared<StubCurrentConfiguration>(),
128@@ -266,12 +307,12 @@
129 }
130
131 // When we upload our 1x1 cursor we should upload a single white pixel and then transparency filling a 64x64 buffer.
132-MATCHER(ContainsASingleWhitePixel, "")
133+MATCHER_P(ContainsASingleWhitePixel, buffersize, "")
134 {
135 auto pixels = static_cast<uint32_t const*>(arg);
136 if (pixels[0] != 0xffffffff)
137 return false;
138- for (int i = 1; i < 64*64; i++)
139+ for (decltype(buffersize) i = 1; i < buffersize; i++)
140 {
141 if (pixels[i] != 0x0)
142 return false;
143@@ -282,23 +323,6 @@
144 TEST_F(MesaCursorTest, show_cursor_pads_missing_data)
145 {
146 using namespace testing;
147-
148- struct SinglePixelCursorImage : public StubCursorImage
149- {
150- geom::Size size() const
151- {
152- return small_cursor_size;
153- }
154- void const* as_argb_8888() const
155- {
156- static uint32_t const pixel = 0xffffffff;
157- return &pixel;
158- }
159-
160- size_t const cursor_side{1};
161- geom::Size const small_cursor_size{cursor_side, cursor_side};
162- };
163-
164 // We expect a full 64x64 pixel write as we will pad missing data with transparency.
165 size_t const height = 64;
166 size_t const width = 64;
167@@ -306,11 +330,34 @@
168 size_t const buffer_size_bytes{height * stride};
169 ON_CALL(mock_gbm, gbm_bo_get_stride(_))
170 .WillByDefault(Return(stride));
171- EXPECT_CALL(mock_gbm, gbm_bo_write(mock_gbm.fake_gbm.bo, ContainsASingleWhitePixel(), buffer_size_bytes));
172+ EXPECT_CALL(mock_gbm, gbm_bo_write(mock_gbm.fake_gbm.bo, ContainsASingleWhitePixel(width*height), buffer_size_bytes));
173
174 cursor.show(SinglePixelCursorImage());
175 }
176
177+TEST_F(MesaCursorTest, pads_missing_data_when_buffer_size_differs)
178+{
179+ using namespace ::testing;
180+
181+ size_t const height = 128;
182+ size_t const width = 128;
183+ size_t const stride = width * 4;
184+ size_t const buffer_size_bytes{height * stride};
185+
186+ ON_CALL(mock_gbm, gbm_bo_get_width(mock_gbm.fake_gbm.bo))
187+ .WillByDefault(Return(width));
188+ ON_CALL(mock_gbm, gbm_bo_get_height(mock_gbm.fake_gbm.bo))
189+ .WillByDefault(Return(height));
190+ ON_CALL(mock_gbm, gbm_bo_get_stride(mock_gbm.fake_gbm.bo))
191+ .WillByDefault(Return(stride));
192+
193+ EXPECT_CALL(mock_gbm, gbm_bo_write(mock_gbm.fake_gbm.bo, ContainsASingleWhitePixel(width*height), buffer_size_bytes));
194+
195+ mgm::Cursor cursor_tmp{mock_gbm.fake_gbm.device, output_container,
196+ std::make_shared<StubCurrentConfiguration>(),
197+ std::make_shared<SinglePixelCursorImage>()};
198+}
199+
200 TEST_F(MesaCursorTest, throws_when_images_are_too_large)
201 {
202 using namespace testing;

Subscribers

People subscribed via source and target branches