Skip to content

Commit 5a9c122

Browse files
authored
Merge pull request #3113 from MirServer/more-virtual-display
Support configuration of virtual displays
2 parents f101708 + e56a9ea commit 5a9c122

File tree

3 files changed

+123
-24
lines changed

3 files changed

+123
-24
lines changed

src/platforms/virtual/display.cpp

+27-10
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,27 @@
1919
#include "display_configuration.h"
2020
#include <mir/log.h>
2121

22+
#include <utility>
23+
2224
namespace mg = mir::graphics;
2325
namespace mgv = mir::graphics::virt;
2426

25-
mgv::Display::Display(std::vector<VirtualOutputConfig> output_sizes)
26-
: outputs{output_sizes}
27+
namespace
28+
{
29+
auto build_configuration(std::vector<mgv::VirtualOutputConfig> const& output_sizes)
30+
-> std::unique_ptr<mgv::DisplayConfiguration>
31+
{
32+
std::vector<mg::DisplayConfigurationOutput> output_configurations;
33+
for (auto const& output: output_sizes)
34+
{
35+
output_configurations.push_back(mgv::DisplayConfiguration::build_output(output));
36+
}
37+
return std::make_unique<mgv::DisplayConfiguration>(output_configurations);
38+
}
39+
}
40+
41+
mgv::Display::Display(std::vector<VirtualOutputConfig> const& output_sizes)
42+
: display_configuration{build_configuration(output_sizes)}
2743
{
2844
}
2945

@@ -33,21 +49,22 @@ void mgv::Display::for_each_display_sync_group(std::function<void(DisplaySyncGro
3349

3450
std::unique_ptr<mg::DisplayConfiguration> mgv::Display::configuration() const
3551
{
36-
std::vector<DisplayConfigurationOutput> output_configurations;
37-
for (auto const& output : outputs)
38-
{
39-
output_configurations.push_back(mgv::DisplayConfiguration::build_output(output));
40-
}
41-
return std::make_unique<mgv::DisplayConfiguration>(output_configurations);
52+
std::lock_guard lock{mutex};
53+
return display_configuration->clone();
4254
}
4355

44-
bool mgv::Display::apply_if_configuration_preserves_display_buffers(mir::graphics::DisplayConfiguration const&)
56+
bool mgv::Display::apply_if_configuration_preserves_display_buffers(mir::graphics::DisplayConfiguration const& conf)
4557
{
58+
configure(conf);
4659
return true;
4760
}
4861

49-
void mgv::Display::configure(mir::graphics::DisplayConfiguration const&)
62+
void mgv::Display::configure(mir::graphics::DisplayConfiguration const& conf)
5063
{
64+
auto const& new_conf = dynamic_cast<DisplayConfiguration const&>(conf);
65+
66+
std::lock_guard lock{mutex};
67+
display_configuration = new_conf.clone();
5168
}
5269

5370
void mgv::Display::register_configuration_change_handler(

src/platforms/virtual/display.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ namespace virt
3030
class Display : public mir::graphics::Display
3131
{
3232
public:
33-
explicit Display(std::vector<VirtualOutputConfig> output_sizes);
33+
explicit Display(std::vector<VirtualOutputConfig> const& output_sizes);
3434
void for_each_display_sync_group(std::function<void(DisplaySyncGroup &)> const& f) override;
3535
std::unique_ptr<mir::graphics::DisplayConfiguration> configuration() const override;
3636
bool apply_if_configuration_preserves_display_buffers(mir::graphics::DisplayConfiguration const& conf) override;
@@ -43,7 +43,8 @@ class Display : public mir::graphics::Display
4343
std::shared_ptr<Cursor> create_hardware_cursor() override;
4444

4545
private:
46-
std::vector<VirtualOutputConfig> outputs;
46+
std::mutex mutable mutex;
47+
std::shared_ptr<DisplayConfiguration> display_configuration;
4748
};
4849
}
4950
}

tests/unit-tests/platforms/virtual/test_display.cpp

+93-12
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "src/platforms/virtual/platform.h"
2222

2323
#include "mir/graphics/display_configuration.h"
24+
#include "mir/graphics/default_display_configuration_policy.h"
2425

2526
#include "mir/test/doubles/null_display_configuration_policy.h"
2627
#include "mir/test/doubles/mock_egl.h"
@@ -31,9 +32,8 @@ namespace mg = mir::graphics;
3132
namespace mgv = mg::virt;
3233
namespace mt = mir::test;
3334
namespace mtd = mt::doubles;
34-
namespace geom = mir::geometry;
3535
using namespace testing;
36-
36+
using namespace mir::geometry;
3737

3838
namespace
3939
{
@@ -58,14 +58,14 @@ class VirtualDisplayTest : public ::testing::Test
5858
TEST_F(VirtualDisplayTest, reports_a_mode_size_that_matches_the_provided_size)
5959
{
6060
auto display = create_display({
61-
mgv::VirtualOutputConfig({geom::Size{1280, 1024}})
61+
mgv::VirtualOutputConfig({Size{1280, 1024}})
6262
});
6363
auto config = display->configuration();
6464
int output_count = 0;
6565
config->for_each_output([&output_count](mg::DisplayConfigurationOutput const& output)
6666
{
6767
EXPECT_THAT(output.modes.size(), Eq(1));
68-
EXPECT_THAT(output.modes[0].size, Eq(geom::Size{1280, 1024}));
68+
EXPECT_THAT(output.modes[0].size, Eq(Size{1280, 1024}));
6969
output_count++;
7070
});
7171

@@ -75,15 +75,15 @@ TEST_F(VirtualDisplayTest, reports_a_mode_size_that_matches_the_provided_size)
7575
TEST_F(VirtualDisplayTest, reports_multiple_mode_sizes_that_matches_the_provided_sizes)
7676
{
7777
auto display = create_display({
78-
mgv::VirtualOutputConfig({geom::Size{1280, 1024}, geom::Size{800, 600}})
78+
mgv::VirtualOutputConfig({Size{1280, 1024}, Size{800, 600}})
7979
});
8080
auto config = display->configuration();
8181
int output_count = 0;
8282
config->for_each_output([&output_count](mg::DisplayConfigurationOutput const& output)
8383
{
8484
EXPECT_THAT(output.modes.size(), Eq(2));
85-
EXPECT_THAT(output.modes[0].size, Eq(geom::Size{1280, 1024}));
86-
EXPECT_THAT(output.modes[1].size, Eq(geom::Size{800, 600}));
85+
EXPECT_THAT(output.modes[0].size, Eq(Size{1280, 1024}));
86+
EXPECT_THAT(output.modes[1].size, Eq(Size{800, 600}));
8787
output_count++;
8888
});
8989

@@ -93,8 +93,8 @@ TEST_F(VirtualDisplayTest, reports_multiple_mode_sizes_that_matches_the_provided
9393
TEST_F(VirtualDisplayTest, reports_multiple_outputs_when_provided_multiple_outputs)
9494
{
9595
auto display = create_display({
96-
mgv::VirtualOutputConfig({geom::Size{1280, 1024}}),
97-
mgv::VirtualOutputConfig({geom::Size{1280, 1024}})
96+
mgv::VirtualOutputConfig({Size{1280, 1024}}),
97+
mgv::VirtualOutputConfig({Size{1280, 1024}})
9898
});
9999
auto config = display->configuration();
100100
int output_count = 0;
@@ -109,8 +109,8 @@ TEST_F(VirtualDisplayTest, reports_multiple_outputs_when_provided_multiple_outpu
109109
TEST_F(VirtualDisplayTest, for_each_display_group_iterates_no_display_groups)
110110
{
111111
auto display = create_display({
112-
mgv::VirtualOutputConfig({geom::Size{1280, 1024}}),
113-
mgv::VirtualOutputConfig({geom::Size{1280, 1024}})
112+
mgv::VirtualOutputConfig({Size{1280, 1024}}),
113+
mgv::VirtualOutputConfig({Size{1280, 1024}})
114114
});
115115

116116
int count = 0;
@@ -122,4 +122,85 @@ TEST_F(VirtualDisplayTest, for_each_display_group_iterates_no_display_groups)
122122
EXPECT_THAT(count, Eq(0));
123123
}
124124

125-
}
125+
}
126+
127+
TEST_F(VirtualDisplayTest, displays_can_be_positioned)
128+
{
129+
auto display = create_display({
130+
mgv::VirtualOutputConfig({Size{1280, 1024}}),
131+
mgv::VirtualOutputConfig({Size{1280, 1024}})
132+
});
133+
134+
{
135+
auto const conf = display->configuration();
136+
137+
mg::SideBySideDisplayConfigurationPolicy{}.apply_to(*conf);
138+
139+
EXPECT_THAT(display->apply_if_configuration_preserves_display_buffers(*conf), IsTrue());
140+
}
141+
142+
auto const conf = display->configuration();
143+
144+
std::vector<Point> positions;
145+
146+
conf->for_each_output([&](mg::DisplayConfigurationOutput const& c) { positions.push_back(c.top_left); });
147+
148+
EXPECT_THAT(positions, ElementsAre(Point{0, 0}, Point{1280, 0}));
149+
}
150+
151+
TEST_F(VirtualDisplayTest, displays_can_be_inverted)
152+
{
153+
auto display = create_display({
154+
mgv::VirtualOutputConfig({Size{1280, 1024}}),
155+
mgv::VirtualOutputConfig({Size{1280, 1024}})
156+
});
157+
158+
{
159+
auto const conf = display->configuration();
160+
161+
conf->for_each_output([](mg::UserDisplayConfigurationOutput& conf) { conf.orientation = mir_orientation_inverted; });
162+
163+
EXPECT_THAT(display->apply_if_configuration_preserves_display_buffers(*conf), IsTrue());
164+
}
165+
166+
auto const conf = display->configuration();
167+
168+
std::vector<MirOrientation> orientations;
169+
170+
conf->for_each_output([&](mg::DisplayConfigurationOutput const& c) { orientations.push_back(c.orientation); });
171+
172+
EXPECT_THAT(orientations, ElementsAre(mir_orientation_inverted, mir_orientation_inverted));
173+
}
174+
175+
TEST_F(VirtualDisplayTest, displays_can_be_resized_without_reallocating_buffers)
176+
{
177+
auto display = create_display({
178+
mgv::VirtualOutputConfig({Size{1280, 1024}, Size{640, 512}}),
179+
mgv::VirtualOutputConfig({Size{1280, 1024}})
180+
});
181+
182+
{
183+
auto const conf = display->configuration();
184+
185+
conf->for_each_output([](mg::UserDisplayConfigurationOutput& conf)
186+
{
187+
if (conf.modes.size() > 1)
188+
{
189+
conf.current_mode_index = 1;
190+
}
191+
});
192+
193+
// This may seem unexpected, but there are no buffers for this platform
194+
EXPECT_THAT(display->apply_if_configuration_preserves_display_buffers(*conf), IsTrue());
195+
display->configure(*conf);
196+
}
197+
198+
auto const conf = display->configuration();
199+
200+
std::vector<Size> sizes;
201+
202+
conf->for_each_output([&](mg::DisplayConfigurationOutput const& c)
203+
{ sizes.push_back(c.modes[c.current_mode_index].size); });
204+
205+
EXPECT_THAT(sizes, ElementsAre(Size{640, 512}, Size{1280, 1024}));
206+
}

0 commit comments

Comments
 (0)