Skip to content

Commit

Permalink
Merge pull request #3056 from MirServer/feature/virtual_output_support
Browse files Browse the repository at this point in the history
Virtual output display platform and tests
  • Loading branch information
AlanGriffiths authored Oct 24, 2023
2 parents 9404475 + 634c940 commit 4a57bc6
Show file tree
Hide file tree
Showing 22 changed files with 1,194 additions and 64 deletions.
30 changes: 30 additions & 0 deletions debian/control
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,20 @@ Description: Display server for Ubuntu - generic EGL rendering platform
Contains the shared libraries required for the Mir server to provide accelerated
client rendering via standard EGL interfaces.

Package: mir-platform-graphics-virtual20
Section: libs
Architecture: linux-any
Multi-Arch: same
Pre-Depends: ${misc:Pre-Depends}
Depends: ${misc:Depends},
${shlibs:Depends},
Description: Display server for Ubuntu - virtual display platform
Mir is a display server running on linux systems, with a focus on efficiency,
robust operation and a well-defined driver model.
.
Contains the shared libraries required for the Mir server to provide virtual
output support.

Package: mir-graphics-drivers-nvidia
Section: libs
Architecture: linux-any
Expand All @@ -325,6 +339,8 @@ Pre-Depends: ${misc:Pre-Depends}
Depends: ${misc:Depends},
mir-platform-graphics-eglstream-kms,
mir-platform-graphics-x,
Recommends:
mir-platform-graphics-virtual,
Description: Display server for Ubuntu - Nvidia driver metapackage
Mir is a display server running on linux systems, with a focus on efficiency,
robust operation and a well-defined driver model.
Expand Down Expand Up @@ -354,6 +370,8 @@ Depends: ${misc:Depends},
mir-platform-graphics-gbm-kms,
mir-platform-graphics-x,
mir-platform-graphics-wayland,
Recommends:
mir-platform-graphics-virtual,
Description: Display server for Ubuntu - desktop driver metapackage
Mir is a display server running on linux systems, with a focus on efficiency,
robust operation and a well-defined driver model.
Expand Down Expand Up @@ -420,6 +438,18 @@ Description: Display server for Ubuntu - EGL rendering provider metapackage
This package depends on the current provider of accelerated client rendering
support via standard EGL interfaces.

Package: mir-platform-graphics-virtual
Section: libs
Architecture: linux-any
Multi-Arch: same
Pre-Depends: ${misc:Pre-Depends}
Depends: mir-platform-graphics-virtual20
Description: Display server for Ubuntu - virtual display provider metapackage
Mir is a display server running on linux systems, with a focus on efficiency,
robust operation and a well-defined driver model.
.
This package depends on the current provider of virtual outputs.

Package: mir-platform-graphics-x
Section: libs
Architecture: linux-any
Expand Down
2 changes: 2 additions & 0 deletions debian/mir-platform-graphics-virtual20.install
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
usr/lib/*/mir/server-platform/server-virtual.so.20

49 changes: 46 additions & 3 deletions examples/miral-shell/spinner/miregl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include <algorithm>
#include <stdexcept>
#include <set>
#include <condition_variable>

class MirEglApp : public WaylandApp
{
Expand All @@ -35,7 +36,7 @@ class MirEglApp : public WaylandApp

EGLSurface create_eglsurface(wl_surface* surface, int width, int height);
void make_current(EGLSurface eglsurface) const;
void swap_buffers(EGLSurface eglsurface) const;
void swap_buffers(EGLSurface eglsurface, wl_surface* wayland_surface) const;
void destroy_surface(EGLSurface eglsurface) const;
void get_surface_size(EGLSurface eglsurface, int* width, int* height) const;

Expand Down Expand Up @@ -99,7 +100,7 @@ void MirEglSurface::egl_make_current()

void MirEglSurface::swap_buffers()
{
mir_egl_app->swap_buffers(eglsurface);
mir_egl_app->swap_buffers(eglsurface, surface());
}

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

void MirEglApp::swap_buffers(EGLSurface eglsurface) const
void MirEglApp::swap_buffers(EGLSurface eglsurface, wl_surface* wayland_surface) const
{
// Taken primarily from src/platforms/wayland/displayclient.cpp
struct FrameSync
{
explicit FrameSync(wl_surface* surface):
surface{surface}
{
callback = wl_surface_frame(surface);
static struct wl_callback_listener const frame_listener =
{
[](void* data, auto... args)
{ static_cast<FrameSync*>(data)->frame_done(args...); },
};
wl_callback_add_listener(callback, &frame_listener, this);
}


~FrameSync()
{
std::unique_lock lock{mutex};
cv.wait_for(lock, std::chrono::milliseconds{100}, [this]{ return posted; });
wl_callback_destroy(callback);
}

void frame_done(wl_callback*, uint32_t)
{
{
std::lock_guard lock{mutex};
posted = true;
}
cv.notify_one();
}

wl_surface* const surface;

wl_callback* callback;
std::mutex mutex;
bool posted = false;
std::condition_variable cv;
};

FrameSync frame_sync{wayland_surface};
eglSwapInterval(egldisplay, 0);
eglSwapBuffers(egldisplay, eglsurface);
}

Expand Down
1 change: 1 addition & 0 deletions src/platforms/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,5 @@ if (MIR_BUILD_PLATFORM_WAYLAND)
add_subdirectory(wayland)
endif()

add_subdirectory(virtual)
add_subdirectory(evdev/)
2 changes: 2 additions & 0 deletions src/platforms/common/server/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ add_library(server_platform_common STATIC
one_shot_device_observer.cpp
cpu_copy_output_surface.cpp
cpu_copy_output_surface.h
options_parsing_helpers.h
options_parsing_helpers.cpp
)

target_include_directories(
Expand Down
99 changes: 99 additions & 0 deletions src/platforms/common/server/options_parsing_helpers.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/*
* Copyright © Canonical Ltd.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License version 2 or 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include "options_parsing_helpers.h"
#include <stdexcept>
#include <boost/throw_exception.hpp>

namespace mgc = mir::graphics::common;
namespace geom = mir::geometry;

namespace
{
auto parse_scale(std::string const& str) -> float
{
try
{
size_t num_end = 0;
float const value = std::stof(str, &num_end);
if (num_end != str.size())
BOOST_THROW_EXCEPTION(std::runtime_error("Scale \"" + str + "\" is not a valid float"));
if (value <= 0.000001)
BOOST_THROW_EXCEPTION(std::runtime_error("Scale must be greater than zero"));
return value;
}
catch (std::invalid_argument const &)
{
BOOST_THROW_EXCEPTION(std::runtime_error("Scale \"" + str + "\" is not a valid float"));
}
catch (std::out_of_range const &)
{
BOOST_THROW_EXCEPTION(std::runtime_error("Scale \"" + str + "\" is out of range"));
}
}

auto parse_size_dimension(std::string const& str) -> int
{
try
{
size_t num_end = 0;
int const value = std::stoi(str, &num_end);
if (num_end != str.size())
BOOST_THROW_EXCEPTION(std::runtime_error("Output dimension \"" + str + "\" is not a valid number"));
if (value <= 0)
BOOST_THROW_EXCEPTION(std::runtime_error("Output dimensions must be greater than zero"));
return value;
}
catch (std::invalid_argument const &)
{
BOOST_THROW_EXCEPTION(std::runtime_error("Output dimension \"" + str + "\" is not a valid number"));
}
catch (std::out_of_range const &)
{
BOOST_THROW_EXCEPTION(std::runtime_error("Output dimension \"" + str + "\" is out of range"));
}
}
}


auto mgc::parse_size(std::string const& str) -> geom::Size
{
auto const x = str.find('x'); // "x" between width and height
if (x == std::string::npos || x <= 0 || x >= str.size() - 1)
BOOST_THROW_EXCEPTION(std::runtime_error("Output size \"" + str + "\" does not have two dimensions"));
return geom::Size{
parse_size_dimension(str.substr(0, x)),
parse_size_dimension(str.substr(x + 1))};
}

auto mgc::parse_size_with_scale(std::string const& str) -> std::tuple<mir::geometry::Size, float>
{
auto const x = str.find('x'); // "x" between width and height
if (x == std::string::npos || x <= 0 || x >= str.size() - 1)
BOOST_THROW_EXCEPTION(std::runtime_error("Output size \"" + str + "\" does not have two dimensions"));
auto const scale_start = str.find('^'); // start of output scale
float scale = 1.0f;
if (scale_start != std::string::npos)
{
if (scale_start >= str.size() - 1)
BOOST_THROW_EXCEPTION(std::runtime_error("In \"" + str + "\", '^' is not followed by a scale"));
scale = parse_scale(str.substr(scale_start + 1, std::string::npos));
}
return {geom::Size{
parse_size_dimension(str.substr(0, x)),
parse_size_dimension(str.substr(x + 1, scale_start - x - 1))},
scale};
}
38 changes: 38 additions & 0 deletions src/platforms/common/server/options_parsing_helpers.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright © Canonical Ltd.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License version 2 or 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef MIR_PLATFORM_OPTIONS_PARSING_HELPERS_H
#define MIR_PLATFORM_OPTIONS_PARSING_HELPERS_H

#include <string>
#include <tuple>
#include <mir/geometry/size.h>

namespace mir
{
namespace graphics
{
namespace common
{

auto parse_size(std::string const& str) -> mir::geometry::Size;
auto parse_size_with_scale(std::string const& str) -> std::tuple<mir::geometry::Size, float>;

}
}
}

#endif //MIR_PLATFORM_OPTIONS_PARSING_HELPERS_H
52 changes: 52 additions & 0 deletions src/platforms/virtual/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
include_directories(
${server_common_include_dirs}
)

configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/symbols.map.in
${CMAKE_CURRENT_BINARY_DIR}/symbols.map
)
set(symbol_map ${CMAKE_CURRENT_BINARY_DIR}/symbols.map)

add_compile_definitions(MIR_LOG_COMPONENT="mir:virtual")

add_library(mirplatformgraphicsvirtualobjects OBJECT
graphics.cpp
platform.cpp
platform.h
display.h
display.cpp
display_configuration.h
display_configuration.cpp
)

target_link_libraries(mirplatformgraphicsvirtualobjects
PUBLIC
mirplatform
mircommon
mircore
)

add_library(mirplatformvirtual MODULE
$<TARGET_OBJECTS:mirplatformgraphicsvirtualobjects>
)

target_link_libraries(
mirplatformvirtual

PRIVATE
mirplatform
server_platform_common
)

set_target_properties(
mirplatformvirtual PROPERTIES
OUTPUT_NAME server-virtual
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/server-modules
PREFIX ""
SUFFIX ".so.${MIR_SERVER_GRAPHICS_PLATFORM_ABI}"
LINK_FLAGS "-Wl,--exclude-libs=ALL -Wl,--version-script,${symbol_map}"
LINK_DEPENDS ${symbol_map}
)

install(TARGETS mirplatformvirtual LIBRARY DESTINATION ${MIR_SERVER_PLATFORM_PATH})
Loading

0 comments on commit 4a57bc6

Please sign in to comment.