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/real_kms_output.h"
20
#include "src/platform/graphics/mesa/page_flipper.h"
22
#include "mir_test/fake_shared.h"
24
#include "mir_test_doubles/mock_drm.h"
28
#include <gtest/gtest.h>
29
#include <gmock/gmock.h>
31
namespace mg = mir::graphics;
32
namespace mgm = mir::graphics::mesa;
33
namespace geom = mir::geometry;
34
namespace mt = mir::test;
35
namespace mtd = mir::test::doubles;
40
class NullPageFlipper : public mgm::PageFlipper
43
bool schedule_flip(uint32_t,uint32_t) { return true; }
44
void wait_for_flip(uint32_t) { }
47
class MockPageFlipper : public mgm::PageFlipper
50
MOCK_METHOD2(schedule_flip, bool(uint32_t,uint32_t));
51
MOCK_METHOD1(wait_for_flip, void(uint32_t));
54
class RealKMSOutputTest : public ::testing::Test
58
: invalid_id{0}, crtc_ids{10, 11},
59
encoder_ids{20, 21}, connector_ids{30, 21},
60
possible_encoder_ids1{encoder_ids[0]},
61
possible_encoder_ids2{encoder_ids[0], encoder_ids[1]}
65
void setup_outputs_connected_crtc()
67
mtd::FakeDRMResources& resources(mock_drm.fake_drm);
68
uint32_t const possible_crtcs_mask{0x1};
72
resources.add_crtc(crtc_ids[0], drmModeModeInfo());
73
resources.add_encoder(encoder_ids[0], crtc_ids[0], possible_crtcs_mask);
74
resources.add_connector(connector_ids[0], DRM_MODE_CONNECTOR_VGA,
75
DRM_MODE_CONNECTED, encoder_ids[0],
76
modes_empty, possible_encoder_ids1, geom::Size());
81
void setup_outputs_no_connected_crtc()
83
mtd::FakeDRMResources& resources(mock_drm.fake_drm);
84
uint32_t const possible_crtcs_mask1{0x1};
85
uint32_t const possible_crtcs_mask_all{0x3};
89
resources.add_crtc(crtc_ids[0], drmModeModeInfo());
90
resources.add_crtc(crtc_ids[1], drmModeModeInfo());
91
resources.add_encoder(encoder_ids[0], crtc_ids[0], possible_crtcs_mask1);
92
resources.add_encoder(encoder_ids[1], invalid_id, possible_crtcs_mask_all);
93
resources.add_connector(connector_ids[0], DRM_MODE_CONNECTOR_Composite,
94
DRM_MODE_CONNECTED, invalid_id,
95
modes_empty, possible_encoder_ids2, geom::Size());
96
resources.add_connector(connector_ids[1], DRM_MODE_CONNECTOR_DVIA,
97
DRM_MODE_CONNECTED, encoder_ids[0],
98
modes_empty, possible_encoder_ids2, geom::Size());
103
testing::NiceMock<mtd::MockDRM> mock_drm;
104
MockPageFlipper mock_page_flipper;
105
NullPageFlipper null_page_flipper;
107
std::vector<drmModeModeInfo> modes_empty;
108
uint32_t const invalid_id;
109
std::vector<uint32_t> const crtc_ids;
110
std::vector<uint32_t> const encoder_ids;
111
std::vector<uint32_t> const connector_ids;
112
std::vector<uint32_t> possible_encoder_ids1;
113
std::vector<uint32_t> possible_encoder_ids2;
118
TEST_F(RealKMSOutputTest, construction_queries_connector)
120
using namespace testing;
122
setup_outputs_connected_crtc();
124
EXPECT_CALL(mock_drm, drmModeGetConnector(_,connector_ids[0]))
127
mgm::RealKMSOutput output{mock_drm.fake_drm.fd(), connector_ids[0],
128
mt::fake_shared(null_page_flipper)};
131
TEST_F(RealKMSOutputTest, operations_use_existing_crtc)
133
using namespace testing;
135
uint32_t const fb_id{67};
137
setup_outputs_connected_crtc();
142
EXPECT_CALL(mock_drm, drmModeSetCrtc(_, crtc_ids[0], fb_id, _, _,
143
Pointee(connector_ids[0]), _, _))
146
EXPECT_CALL(mock_page_flipper, schedule_flip(crtc_ids[0], fb_id))
148
.WillOnce(Return(true));
150
EXPECT_CALL(mock_page_flipper, wait_for_flip(crtc_ids[0]))
153
EXPECT_CALL(mock_drm, drmModeSetCrtc(_, crtc_ids[0], Ne(fb_id), _, _,
154
Pointee(connector_ids[0]), _, _))
158
mgm::RealKMSOutput output{mock_drm.fake_drm.fd(), connector_ids[0],
159
mt::fake_shared(mock_page_flipper)};
161
EXPECT_TRUE(output.set_crtc(fb_id));
162
EXPECT_TRUE(output.schedule_page_flip(fb_id));
163
output.wait_for_page_flip();
166
TEST_F(RealKMSOutputTest, operations_use_possible_crtc)
168
using namespace testing;
170
uint32_t const fb_id{67};
172
setup_outputs_no_connected_crtc();
177
EXPECT_CALL(mock_drm, drmModeSetCrtc(_, crtc_ids[1], fb_id, _, _,
178
Pointee(connector_ids[0]), _, _))
181
EXPECT_CALL(mock_page_flipper, schedule_flip(crtc_ids[1], fb_id))
183
.WillOnce(Return(true));
185
EXPECT_CALL(mock_page_flipper, wait_for_flip(crtc_ids[1]))
188
EXPECT_CALL(mock_drm, drmModeSetCrtc(_, 0, 0, _, _,
189
Pointee(connector_ids[0]), _, _))
193
mgm::RealKMSOutput output{mock_drm.fake_drm.fd(), connector_ids[0],
194
mt::fake_shared(mock_page_flipper)};
196
EXPECT_TRUE(output.set_crtc(fb_id));
197
EXPECT_TRUE(output.schedule_page_flip(fb_id));
198
output.wait_for_page_flip();
201
TEST_F(RealKMSOutputTest, set_crtc_failure_is_handled_gracefully)
203
using namespace testing;
205
uint32_t const fb_id{67};
207
setup_outputs_connected_crtc();
212
EXPECT_CALL(mock_drm, drmModeSetCrtc(_, crtc_ids[0], fb_id, _, _, _, _, _))
214
.WillOnce(Return(1));
216
EXPECT_CALL(mock_page_flipper, schedule_flip(_, _))
219
EXPECT_CALL(mock_page_flipper, wait_for_flip(_))
222
EXPECT_CALL(mock_drm, drmModeSetCrtc(_, _, _, _, _, _, _, _))
226
mgm::RealKMSOutput output{mock_drm.fake_drm.fd(), connector_ids[0],
227
mt::fake_shared(mock_page_flipper)};
229
EXPECT_FALSE(output.set_crtc(fb_id));
231
output.schedule_page_flip(fb_id);
232
}, std::runtime_error);
234
output.wait_for_page_flip();
235
}, std::runtime_error);
238
TEST_F(RealKMSOutputTest, clear_crtc_gets_crtc_if_none_is_current)
240
using namespace testing;
242
setup_outputs_connected_crtc();
244
mgm::RealKMSOutput output{mock_drm.fake_drm.fd(), connector_ids[0],
245
mt::fake_shared(mock_page_flipper)};
247
EXPECT_CALL(mock_drm, drmModeSetCrtc(_, crtc_ids[0], 0, 0, 0, nullptr, 0, nullptr))
249
.WillOnce(Return(0));
254
TEST_F(RealKMSOutputTest, clear_crtc_does_not_throw_if_no_crtc_is_found)
256
using namespace testing;
258
mtd::FakeDRMResources& resources(mock_drm.fake_drm);
259
uint32_t const possible_crtcs_mask_empty{0x0};
263
resources.add_encoder(encoder_ids[0], invalid_id, possible_crtcs_mask_empty);
264
resources.add_connector(connector_ids[0], DRM_MODE_CONNECTOR_VGA,
265
DRM_MODE_CONNECTED, encoder_ids[0],
266
modes_empty, possible_encoder_ids1, geom::Size());
270
mgm::RealKMSOutput output{mock_drm.fake_drm.fd(), connector_ids[0],
271
mt::fake_shared(mock_page_flipper)};
273
EXPECT_CALL(mock_drm, drmModeSetCrtc(_, _, 0, 0, 0, nullptr, 0, nullptr))
279
TEST_F(RealKMSOutputTest, clear_crtc_throws_if_drm_call_fails)
281
using namespace testing;
283
setup_outputs_connected_crtc();
285
mgm::RealKMSOutput output{mock_drm.fake_drm.fd(), connector_ids[0],
286
mt::fake_shared(mock_page_flipper)};
288
EXPECT_CALL(mock_drm, drmModeSetCrtc(_, crtc_ids[0], 0, 0, 0, nullptr, 0, nullptr))
290
.WillOnce(Return(-1));
294
}, std::runtime_error);