2
* Copyright © 2013 Canonical Ltd.
4
* This program is free software: you can redistribute it and/or modify
5
* it under the terms of the GNU General Public License version 3 as
6
* published by the Free Software Foundation.
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 General Public License for more details.
13
* You should have received a copy of the GNU General Public License
14
* along with this program. If not, see <http://www.gnu.org/licenses/>.
16
* Authored by: Alexandros Frantzis <alexandros.frantzis@canonical.com>
19
#include "src/platform/graphics/mesa/cursor.h"
20
#include "src/platform/graphics/mesa/kms_output.h"
21
#include "src/platform/graphics/mesa/kms_output_container.h"
22
#include "src/platform/graphics/mesa/kms_display_configuration.h"
24
#include "mir_test_doubles/mock_gbm.h"
26
#include <gtest/gtest.h>
27
#include <gmock/gmock.h>
29
#include <unordered_map>
31
namespace mg = mir::graphics;
32
namespace mgm = mir::graphics::mesa;
33
namespace geom = mir::geometry;
34
namespace mtd = mir::test::doubles;
39
struct MockKMSOutput : public mgm::KMSOutput
41
MOCK_METHOD0(reset, void());
42
MOCK_METHOD2(configure, void(geom::Displacement, size_t));
43
MOCK_CONST_METHOD0(size, geom::Size());
45
MOCK_METHOD1(set_crtc, bool(uint32_t));
46
MOCK_METHOD0(clear_crtc, void());
47
MOCK_METHOD1(schedule_page_flip, bool(uint32_t));
48
MOCK_METHOD0(wait_for_page_flip, void());
50
MOCK_METHOD1(set_cursor, void(gbm_bo*));
51
MOCK_METHOD1(move_cursor, void(geom::Point));
52
MOCK_METHOD0(clear_cursor, void());
53
MOCK_CONST_METHOD0(has_cursor, bool());
55
MOCK_METHOD1(set_power_mode, void(MirPowerMode));
58
struct StubKMSOutputContainer : public mgm::KMSOutputContainer
60
StubKMSOutputContainer()
62
{10, std::make_shared<testing::NiceMock<MockKMSOutput>>()},
63
{11, std::make_shared<testing::NiceMock<MockKMSOutput>>()}}
67
std::shared_ptr<mgm::KMSOutput> get_kms_output_for(uint32_t connector_id)
69
return outputs[connector_id];
72
void for_each_output(std::function<void(mgm::KMSOutput&)> functor) const
74
for (auto const& pair : outputs)
75
functor(*pair.second);
78
void verify_and_clear_expectations()
80
for (auto const& pair : outputs)
81
::testing::Mock::VerifyAndClearExpectations(pair.second.get());
84
std::unordered_map<uint32_t,std::shared_ptr<testing::NiceMock<MockKMSOutput>>> outputs;
87
struct StubKMSDisplayConfiguration : public mgm::KMSDisplayConfiguration
89
StubKMSDisplayConfiguration()
94
mg::DisplayConfigurationOutputId{10},
96
mg::DisplayConfigurationOutputType::vga,
99
{geom::Size{10, 20}, 59.9},
100
{geom::Size{200, 100}, 59.9},
103
geom::Size{324, 642},
113
mg::DisplayConfigurationOutputId{11},
115
mg::DisplayConfigurationOutputType::vga,
118
{geom::Size{200, 200}, 59.9},
119
{geom::Size{100, 200}, 59.9},
122
geom::Size{566, 111},
125
geom::Point{100, 50},
132
void for_each_card(std::function<void(mg::DisplayConfigurationCard const&)> f) const
134
f({card_id, outputs.size()});
137
void for_each_output(std::function<void(mg::DisplayConfigurationOutput const&)> f) const
139
for (auto const& output : outputs)
143
void configure_output(mg::DisplayConfigurationOutputId, bool,
144
geom::Point, size_t, MirPowerMode)
148
uint32_t get_kms_connector_id(mg::DisplayConfigurationOutputId id) const
150
return id.as_value();
153
size_t get_kms_mode_index(mg::DisplayConfigurationOutputId, size_t conf_mode_index) const
155
return conf_mode_index;
162
mg::DisplayConfigurationCardId card_id;
163
std::vector<mg::DisplayConfigurationOutput> outputs;
166
struct StubCurrentConfiguration : public mgm::CurrentConfiguration
168
void with_current_configuration_do(
169
std::function<void(mgm::KMSDisplayConfiguration const&)> const& exec)
174
StubKMSDisplayConfiguration conf;
177
struct MesaCursorTest : public ::testing::Test
180
: cursor{mock_gbm.fake_gbm.device, output_container,
181
std::make_shared<StubCurrentConfiguration>()}
185
testing::NiceMock<mtd::MockGBM> mock_gbm;
186
StubKMSOutputContainer output_container;
192
TEST_F(MesaCursorTest, creates_cursor_bo_image)
194
size_t const cursor_side{64};
195
EXPECT_CALL(mock_gbm, gbm_bo_create(mock_gbm.fake_gbm.device,
196
cursor_side, cursor_side,
198
GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE));
200
mgm::Cursor cursor_tmp{mock_gbm.fake_gbm.device, output_container,
201
std::make_shared<StubCurrentConfiguration>()};
204
TEST_F(MesaCursorTest, set_cursor_writes_to_bo)
206
using namespace testing;
208
void* const image{reinterpret_cast<void*>(0x5678)};
209
size_t const cursor_side{64};
210
geom::Size const cursor_size{cursor_side, cursor_side};
211
size_t const cursor_size_bytes{cursor_side * cursor_side * sizeof(uint32_t)};
213
EXPECT_CALL(mock_gbm, gbm_bo_write(mock_gbm.fake_gbm.bo, image, cursor_size_bytes));
215
cursor.set_image(image, cursor_size);
218
TEST_F(MesaCursorTest, set_cursor_throws_on_incorrect_size)
220
using namespace testing;
222
void* const image{reinterpret_cast<void*>(0x5678)};
223
size_t const cursor_side{48};
224
geom::Size const cursor_size{cursor_side, cursor_side};
227
cursor.set_image(image, cursor_size);
231
TEST_F(MesaCursorTest, forces_cursor_state_on_construction)
233
using namespace testing;
235
EXPECT_CALL(*output_container.outputs[10], move_cursor(geom::Point{0,0}));
236
EXPECT_CALL(*output_container.outputs[10], set_cursor(_));
237
EXPECT_CALL(*output_container.outputs[11], clear_cursor());
239
/* No checking of existing cursor state */
240
EXPECT_CALL(*output_container.outputs[10], has_cursor()).Times(0);
241
EXPECT_CALL(*output_container.outputs[11], has_cursor()).Times(0);
243
mgm::Cursor cursor_tmp{mock_gbm.fake_gbm.device, output_container,
244
std::make_shared<StubCurrentConfiguration>()};
246
output_container.verify_and_clear_expectations();
250
TEST_F(MesaCursorTest, move_to_sets_clears_cursor_if_needed)
252
using namespace testing;
254
EXPECT_CALL(*output_container.outputs[10], has_cursor())
255
.WillOnce(Return(false));
256
EXPECT_CALL(*output_container.outputs[10], set_cursor(_));
258
EXPECT_CALL(*output_container.outputs[11], has_cursor())
259
.WillOnce(Return(true));
260
EXPECT_CALL(*output_container.outputs[11], clear_cursor());
262
cursor.move_to({10, 10});
264
output_container.verify_and_clear_expectations();
267
TEST_F(MesaCursorTest, move_to_doesnt_set_clear_cursor_if_not_needed)
269
using namespace testing;
271
EXPECT_CALL(*output_container.outputs[10], has_cursor())
272
.WillOnce(Return(true));
273
EXPECT_CALL(*output_container.outputs[10], set_cursor(_))
276
EXPECT_CALL(*output_container.outputs[11], has_cursor())
277
.WillOnce(Return(false));
278
EXPECT_CALL(*output_container.outputs[11], clear_cursor())
281
cursor.move_to({10, 10});
283
output_container.verify_and_clear_expectations();
286
TEST_F(MesaCursorTest, move_to_moves_cursor_to_right_output)
288
using namespace testing;
290
EXPECT_CALL(*output_container.outputs[10], move_cursor(geom::Point{10,10}));
291
EXPECT_CALL(*output_container.outputs[11], move_cursor(_))
294
cursor.move_to({10, 10});
296
output_container.verify_and_clear_expectations();
298
EXPECT_CALL(*output_container.outputs[10], move_cursor(_))
300
EXPECT_CALL(*output_container.outputs[11], move_cursor(geom::Point{50,100}));
302
cursor.move_to({150, 150});
304
output_container.verify_and_clear_expectations();
306
EXPECT_CALL(*output_container.outputs[10], move_cursor(geom::Point{150,75}));
307
EXPECT_CALL(*output_container.outputs[11], move_cursor(geom::Point{50,25}));
309
cursor.move_to({150, 75});
311
output_container.verify_and_clear_expectations();
313
EXPECT_CALL(*output_container.outputs[10], move_cursor(_))
315
EXPECT_CALL(*output_container.outputs[11], move_cursor(_))
318
cursor.move_to({-1, -1});
320
output_container.verify_and_clear_expectations();
323
TEST_F(MesaCursorTest, shows_at_last_known_position)
325
using namespace testing;
327
EXPECT_CALL(*output_container.outputs[10], move_cursor(geom::Point{150,75}));
328
EXPECT_CALL(*output_container.outputs[11], move_cursor(geom::Point{50,25}));
330
cursor.move_to({150, 75});
332
output_container.verify_and_clear_expectations();
334
EXPECT_CALL(*output_container.outputs[10], move_cursor(geom::Point{150,75}));
335
EXPECT_CALL(*output_container.outputs[11], move_cursor(geom::Point{50,25}));
337
cursor.show_at_last_known_position();
339
output_container.verify_and_clear_expectations();
342
TEST_F(MesaCursorTest, hides_cursor_in_all_outputs)
344
using namespace testing;
346
EXPECT_CALL(*output_container.outputs[10], clear_cursor());
347
EXPECT_CALL(*output_container.outputs[11], clear_cursor());
351
output_container.verify_and_clear_expectations();
354
TEST_F(MesaCursorTest, clears_cursor_on_exit)
356
using namespace testing;
358
EXPECT_CALL(*output_container.outputs[10], clear_cursor());
359
EXPECT_CALL(*output_container.outputs[11], clear_cursor());