Skip to content

Commit 4a57bc6

Browse files
Merge pull request #3056 from MirServer/feature/virtual_output_support
Virtual output display platform and tests
2 parents 9404475 + 634c940 commit 4a57bc6

22 files changed

+1194
-64
lines changed

debian/control

+30
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,20 @@ Description: Display server for Ubuntu - generic EGL rendering platform
317317
Contains the shared libraries required for the Mir server to provide accelerated
318318
client rendering via standard EGL interfaces.
319319

320+
Package: mir-platform-graphics-virtual20
321+
Section: libs
322+
Architecture: linux-any
323+
Multi-Arch: same
324+
Pre-Depends: ${misc:Pre-Depends}
325+
Depends: ${misc:Depends},
326+
${shlibs:Depends},
327+
Description: Display server for Ubuntu - virtual display platform
328+
Mir is a display server running on linux systems, with a focus on efficiency,
329+
robust operation and a well-defined driver model.
330+
.
331+
Contains the shared libraries required for the Mir server to provide virtual
332+
output support.
333+
320334
Package: mir-graphics-drivers-nvidia
321335
Section: libs
322336
Architecture: linux-any
@@ -325,6 +339,8 @@ Pre-Depends: ${misc:Pre-Depends}
325339
Depends: ${misc:Depends},
326340
mir-platform-graphics-eglstream-kms,
327341
mir-platform-graphics-x,
342+
Recommends:
343+
mir-platform-graphics-virtual,
328344
Description: Display server for Ubuntu - Nvidia driver metapackage
329345
Mir is a display server running on linux systems, with a focus on efficiency,
330346
robust operation and a well-defined driver model.
@@ -354,6 +370,8 @@ Depends: ${misc:Depends},
354370
mir-platform-graphics-gbm-kms,
355371
mir-platform-graphics-x,
356372
mir-platform-graphics-wayland,
373+
Recommends:
374+
mir-platform-graphics-virtual,
357375
Description: Display server for Ubuntu - desktop driver metapackage
358376
Mir is a display server running on linux systems, with a focus on efficiency,
359377
robust operation and a well-defined driver model.
@@ -420,6 +438,18 @@ Description: Display server for Ubuntu - EGL rendering provider metapackage
420438
This package depends on the current provider of accelerated client rendering
421439
support via standard EGL interfaces.
422440

441+
Package: mir-platform-graphics-virtual
442+
Section: libs
443+
Architecture: linux-any
444+
Multi-Arch: same
445+
Pre-Depends: ${misc:Pre-Depends}
446+
Depends: mir-platform-graphics-virtual20
447+
Description: Display server for Ubuntu - virtual display provider metapackage
448+
Mir is a display server running on linux systems, with a focus on efficiency,
449+
robust operation and a well-defined driver model.
450+
.
451+
This package depends on the current provider of virtual outputs.
452+
423453
Package: mir-platform-graphics-x
424454
Section: libs
425455
Architecture: linux-any
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
usr/lib/*/mir/server-platform/server-virtual.so.20
2+

examples/miral-shell/spinner/miregl.cpp

+46-3
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include <algorithm>
2525
#include <stdexcept>
2626
#include <set>
27+
#include <condition_variable>
2728

2829
class MirEglApp : public WaylandApp
2930
{
@@ -35,7 +36,7 @@ class MirEglApp : public WaylandApp
3536

3637
EGLSurface create_eglsurface(wl_surface* surface, int width, int height);
3738
void make_current(EGLSurface eglsurface) const;
38-
void swap_buffers(EGLSurface eglsurface) const;
39+
void swap_buffers(EGLSurface eglsurface, wl_surface* wayland_surface) const;
3940
void destroy_surface(EGLSurface eglsurface) const;
4041
void get_surface_size(EGLSurface eglsurface, int* width, int* height) const;
4142

@@ -99,7 +100,7 @@ void MirEglSurface::egl_make_current()
99100

100101
void MirEglSurface::swap_buffers()
101102
{
102-
mir_egl_app->swap_buffers(eglsurface);
103+
mir_egl_app->swap_buffers(eglsurface, surface());
103104
}
104105

105106
MirEglApp::MirEglApp(wl_display* display) :
@@ -192,8 +193,50 @@ void MirEglApp::make_current(EGLSurface eglsurface) const
192193
throw std::runtime_error("Can't eglMakeCurrent");
193194
}
194195

195-
void MirEglApp::swap_buffers(EGLSurface eglsurface) const
196+
void MirEglApp::swap_buffers(EGLSurface eglsurface, wl_surface* wayland_surface) const
196197
{
198+
// Taken primarily from src/platforms/wayland/displayclient.cpp
199+
struct FrameSync
200+
{
201+
explicit FrameSync(wl_surface* surface):
202+
surface{surface}
203+
{
204+
callback = wl_surface_frame(surface);
205+
static struct wl_callback_listener const frame_listener =
206+
{
207+
[](void* data, auto... args)
208+
{ static_cast<FrameSync*>(data)->frame_done(args...); },
209+
};
210+
wl_callback_add_listener(callback, &frame_listener, this);
211+
}
212+
213+
214+
~FrameSync()
215+
{
216+
std::unique_lock lock{mutex};
217+
cv.wait_for(lock, std::chrono::milliseconds{100}, [this]{ return posted; });
218+
wl_callback_destroy(callback);
219+
}
220+
221+
void frame_done(wl_callback*, uint32_t)
222+
{
223+
{
224+
std::lock_guard lock{mutex};
225+
posted = true;
226+
}
227+
cv.notify_one();
228+
}
229+
230+
wl_surface* const surface;
231+
232+
wl_callback* callback;
233+
std::mutex mutex;
234+
bool posted = false;
235+
std::condition_variable cv;
236+
};
237+
238+
FrameSync frame_sync{wayland_surface};
239+
eglSwapInterval(egldisplay, 0);
197240
eglSwapBuffers(egldisplay, eglsurface);
198241
}
199242

src/platforms/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -67,4 +67,5 @@ if (MIR_BUILD_PLATFORM_WAYLAND)
6767
add_subdirectory(wayland)
6868
endif()
6969

70+
add_subdirectory(virtual)
7071
add_subdirectory(evdev/)

src/platforms/common/server/CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ add_library(server_platform_common STATIC
1414
one_shot_device_observer.cpp
1515
cpu_copy_output_surface.cpp
1616
cpu_copy_output_surface.h
17+
options_parsing_helpers.h
18+
options_parsing_helpers.cpp
1719
)
1820

1921
target_include_directories(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/*
2+
* Copyright © 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 2 or 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+
17+
#include "options_parsing_helpers.h"
18+
#include <stdexcept>
19+
#include <boost/throw_exception.hpp>
20+
21+
namespace mgc = mir::graphics::common;
22+
namespace geom = mir::geometry;
23+
24+
namespace
25+
{
26+
auto parse_scale(std::string const& str) -> float
27+
{
28+
try
29+
{
30+
size_t num_end = 0;
31+
float const value = std::stof(str, &num_end);
32+
if (num_end != str.size())
33+
BOOST_THROW_EXCEPTION(std::runtime_error("Scale \"" + str + "\" is not a valid float"));
34+
if (value <= 0.000001)
35+
BOOST_THROW_EXCEPTION(std::runtime_error("Scale must be greater than zero"));
36+
return value;
37+
}
38+
catch (std::invalid_argument const &)
39+
{
40+
BOOST_THROW_EXCEPTION(std::runtime_error("Scale \"" + str + "\" is not a valid float"));
41+
}
42+
catch (std::out_of_range const &)
43+
{
44+
BOOST_THROW_EXCEPTION(std::runtime_error("Scale \"" + str + "\" is out of range"));
45+
}
46+
}
47+
48+
auto parse_size_dimension(std::string const& str) -> int
49+
{
50+
try
51+
{
52+
size_t num_end = 0;
53+
int const value = std::stoi(str, &num_end);
54+
if (num_end != str.size())
55+
BOOST_THROW_EXCEPTION(std::runtime_error("Output dimension \"" + str + "\" is not a valid number"));
56+
if (value <= 0)
57+
BOOST_THROW_EXCEPTION(std::runtime_error("Output dimensions must be greater than zero"));
58+
return value;
59+
}
60+
catch (std::invalid_argument const &)
61+
{
62+
BOOST_THROW_EXCEPTION(std::runtime_error("Output dimension \"" + str + "\" is not a valid number"));
63+
}
64+
catch (std::out_of_range const &)
65+
{
66+
BOOST_THROW_EXCEPTION(std::runtime_error("Output dimension \"" + str + "\" is out of range"));
67+
}
68+
}
69+
}
70+
71+
72+
auto mgc::parse_size(std::string const& str) -> geom::Size
73+
{
74+
auto const x = str.find('x'); // "x" between width and height
75+
if (x == std::string::npos || x <= 0 || x >= str.size() - 1)
76+
BOOST_THROW_EXCEPTION(std::runtime_error("Output size \"" + str + "\" does not have two dimensions"));
77+
return geom::Size{
78+
parse_size_dimension(str.substr(0, x)),
79+
parse_size_dimension(str.substr(x + 1))};
80+
}
81+
82+
auto mgc::parse_size_with_scale(std::string const& str) -> std::tuple<mir::geometry::Size, float>
83+
{
84+
auto const x = str.find('x'); // "x" between width and height
85+
if (x == std::string::npos || x <= 0 || x >= str.size() - 1)
86+
BOOST_THROW_EXCEPTION(std::runtime_error("Output size \"" + str + "\" does not have two dimensions"));
87+
auto const scale_start = str.find('^'); // start of output scale
88+
float scale = 1.0f;
89+
if (scale_start != std::string::npos)
90+
{
91+
if (scale_start >= str.size() - 1)
92+
BOOST_THROW_EXCEPTION(std::runtime_error("In \"" + str + "\", '^' is not followed by a scale"));
93+
scale = parse_scale(str.substr(scale_start + 1, std::string::npos));
94+
}
95+
return {geom::Size{
96+
parse_size_dimension(str.substr(0, x)),
97+
parse_size_dimension(str.substr(x + 1, scale_start - x - 1))},
98+
scale};
99+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* Copyright © 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 2 or 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+
17+
#ifndef MIR_PLATFORM_OPTIONS_PARSING_HELPERS_H
18+
#define MIR_PLATFORM_OPTIONS_PARSING_HELPERS_H
19+
20+
#include <string>
21+
#include <tuple>
22+
#include <mir/geometry/size.h>
23+
24+
namespace mir
25+
{
26+
namespace graphics
27+
{
28+
namespace common
29+
{
30+
31+
auto parse_size(std::string const& str) -> mir::geometry::Size;
32+
auto parse_size_with_scale(std::string const& str) -> std::tuple<mir::geometry::Size, float>;
33+
34+
}
35+
}
36+
}
37+
38+
#endif //MIR_PLATFORM_OPTIONS_PARSING_HELPERS_H

src/platforms/virtual/CMakeLists.txt

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
include_directories(
2+
${server_common_include_dirs}
3+
)
4+
5+
configure_file(
6+
${CMAKE_CURRENT_SOURCE_DIR}/symbols.map.in
7+
${CMAKE_CURRENT_BINARY_DIR}/symbols.map
8+
)
9+
set(symbol_map ${CMAKE_CURRENT_BINARY_DIR}/symbols.map)
10+
11+
add_compile_definitions(MIR_LOG_COMPONENT="mir:virtual")
12+
13+
add_library(mirplatformgraphicsvirtualobjects OBJECT
14+
graphics.cpp
15+
platform.cpp
16+
platform.h
17+
display.h
18+
display.cpp
19+
display_configuration.h
20+
display_configuration.cpp
21+
)
22+
23+
target_link_libraries(mirplatformgraphicsvirtualobjects
24+
PUBLIC
25+
mirplatform
26+
mircommon
27+
mircore
28+
)
29+
30+
add_library(mirplatformvirtual MODULE
31+
$<TARGET_OBJECTS:mirplatformgraphicsvirtualobjects>
32+
)
33+
34+
target_link_libraries(
35+
mirplatformvirtual
36+
37+
PRIVATE
38+
mirplatform
39+
server_platform_common
40+
)
41+
42+
set_target_properties(
43+
mirplatformvirtual PROPERTIES
44+
OUTPUT_NAME server-virtual
45+
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/server-modules
46+
PREFIX ""
47+
SUFFIX ".so.${MIR_SERVER_GRAPHICS_PLATFORM_ABI}"
48+
LINK_FLAGS "-Wl,--exclude-libs=ALL -Wl,--version-script,${symbol_map}"
49+
LINK_DEPENDS ${symbol_map}
50+
)
51+
52+
install(TARGETS mirplatformvirtual LIBRARY DESTINATION ${MIR_SERVER_PLATFORM_PATH})

0 commit comments

Comments
 (0)